qlaw/serve.py. Start it locally:
configure_research() — dspy.configure has an owner-thread rule and must not be called inside request handlers. Use dspy.context for per-request overrides.
Endpoints
POST /seed
GraphState. Errors map through the DSPy 3.3.0 exception hierarchy (see “Error mapping” below).
POST /engine
outputs uses Prediction.toDict() — DSPy 3.3.0 has no Prediction.model_dump().
max_depth is not a request field. It is a constructor argument on ReasoningEngine and ReasoningLoop.
POST /chat/stream
session_id to a bounded, independently locked QlawChat in ChatSessionStore. Missing or expired entries start a fresh conversation. history is used only to bootstrap a fresh instance for HTTP compatibility. Later turns use the instance-owned history.
SSE frames
- Non-
Predictionyields areStatusMessageand stream events.ChatStatusProviderturns tool start and end into compact status lines. - ReActV2 emits its final answer as
submittool-call arguments, so token-level streaming ofanswerdoes not apply. Surface tool activity asstatusevents and the complete answer in thedoneframe. - The
doneframe carries the final graph. Chat tools expand the graph during the agent run, so the client must adoptdone.graph.
GET /config
Returns {"model": "..."} from OPENAI_MODEL (default deepseek-v4-flash). Credentials are never exposed. The web client reads this to display the active model id.
Error mapping
DSPy 3.3.0 normalizes LM errors underdspy.LMError. Catch subclasses and map:
For the streamed
/chat/stream route, the response has already started when an error occurs mid-stream. HTTPException is not an option there — the generator catches the exception and emits:
Streaming configuration
Relevant DSPy settings:dspy.configure(allow_tool_async_sync_conversion=True)— allow sync tool implementations in async paths.async_max_workers=...— control async concurrency.dspy.asyncify(fn)— wrap a sync function for the async path.
dspy.stream does not exist in 3.3.0. Streaming goes through dspy.streamify(program, status_message_provider=...), which returns an async generator ending with the final dspy.Prediction.