Skip to content

tdfs4ds.serve.openai_router

tdfs4ds.serve.openai_router

OpenAI-compatible HTTP surface for the two tdfs4ds agents.

Exposes the minimal slice of the OpenAI API that chat clients (the openai SDK, Open WebUI, LibreChat, …) need:

GET  /v1/models               → list the two model ids
POST /v1/chat/completions      → run the selected agent

The model field of a chat-completions request selects the agent:

"tdfs4ds-consumer"          → consumer_agent()        (feature-store RAG)
"tdfs4ds-query-optimizer"   → query_optimizer_agent() (SQL EXPLAIN/optimize)

The latest user message becomes the agent's question. For the query optimizer the user pastes the SQL inline in that message — the optimizer parses it out of the turn, so no schema extension is needed.

Conversation memory is owned by the agents (LangGraph MemorySaver keyed by thread_id). A request that wants continuity sets the OpenAI user field to a stable id; otherwise each request gets a fresh thread_id and is effectively stateless.

logger module-attribute

logger = getLogger('tdfs4ds.serve')

MODEL_CONSUMER module-attribute

MODEL_CONSUMER = 'tdfs4ds-consumer'

MODEL_QUERY_OPTIMIZER module-attribute

MODEL_QUERY_OPTIMIZER = 'tdfs4ds-query-optimizer'

MODELS module-attribute

MODELS = (MODEL_CONSUMER, MODEL_QUERY_OPTIMIZER)

router module-attribute

router = APIRouter()

ChatMessage

Bases: BaseModel

role instance-attribute

role: str

content class-attribute instance-attribute

content: str = ''

ChatCompletionRequest

Bases: BaseModel

model instance-attribute

model: str

messages instance-attribute

messages: list[ChatMessage]

stream class-attribute instance-attribute

stream: bool = False

user class-attribute instance-attribute

user: str | None = None

temperature class-attribute instance-attribute

temperature: float | None = None

top_p class-attribute instance-attribute

top_p: float | None = None

max_tokens class-attribute instance-attribute

max_tokens: int | None = None

_latest_user_message

_latest_user_message(messages: list[ChatMessage]) -> str

Return the content of the last message with role 'user'.

_thread_id

_thread_id(req: ChatCompletionRequest) -> str

Stable thread id from the OpenAI user field, else a fresh uuid.

_run_agent

_run_agent(req: ChatCompletionRequest, base_url: str = '') -> tuple[str, dict]

Dispatch to the selected agent. Returns (answer, token_usage).

base_url (e.g. http://host:8000) is used to turn the query optimizer's relative report_path into a clickable download URL.

_link_report(answer: str, skill_result: dict, base_url: str) -> str

Rewrite the optimizer's `report_path` reference into a download URL.

node_synthesize renders **Full report:** `{domain}/{file}.md`; here we turn it into **Full report:** {base_url}/reports/{domain}/{file}.md so the user can click / curl it. No-op when there is no report path or no base.

_consumer_token_usage

_consumer_token_usage() -> dict

_usage_block

_usage_block(usage: dict) -> dict

_completion_response

_completion_response(model: str, answer: str, usage: dict) -> dict

_sse

_sse(payload: dict) -> str

_stream_response

_stream_response(model: str, answer: str)

Emit the answer as a single OpenAI chat.completion.chunk + [DONE].

The agents return a complete string (not a token stream), so v1 streaming sends one content chunk. Clients that require stream:true still work.

list_models async

list_models()

chat_completions async

chat_completions(req: ChatCompletionRequest, request: Request)