Skip to content

feat(api): a per-run hook for callbacks and context - #79

Merged
ciaransweet merged 1 commit into
mainfrom
feat/api-turn-context
Aug 13, 2026
Merged

feat(api): a per-run hook for callbacks and context#79
ciaransweet merged 1 commit into
mainfrom
feat/api-turn-context

Conversation

@ciaransweet

Copy link
Copy Markdown
Contributor

create_router had no seam for what a host puts around a run. create_run
called stream_turn(agent, question, thread_id) with no config and entered only
user_credentials inside the SSE generator — so a deployment could serve the
agent over HTTP but could not trace it.

The hook

router = create_router(provider, turn_context=traced)
app.include_router(router)

Called per run with the request and both ids, entered inside the stream, and
whatever it yields becomes the turn's runnable config. create_app takes the
same argument and forwards it. Omit it and nothing changes.

Why a context manager, not a config factory

The two things a host wants here differ in kind. A tracing callback is a
value handed to the turn. A correlation id stamped onto the outbound MCP
calls — a header on every call a turn makes, read by an httpx event hook at
request time — is a context variable, which has to be set for the duration
rather than passed.

A factory returning a config covers the first and not the second. A context
manager covers both, and yields the config on the way in.

Both share a lifetime requirement, which is why this is entered beside
user_credentials rather than wrapped around the route: by the time the first
tool is called, the request handler has long returned, so anything scoped to
its stack is already gone.

Tests

Three, each pinning a property that would otherwise regress silently:

  • it is given the request and both ids, and it is left on the way out — a
    wrapper that never exits leaks whatever it opened, once per run;
  • the yielded config reaches the graph run: a callback handler that exists
    only inside it records a chain start, which it cannot do if the config is
    dropped;
  • a ContextVar set inside it is visible from the tool call, which is the
    property a config factory could not have delivered and the reason for the
    shape.

332 tests pass, lint clean.

What it unblocks

dss-agentic-ai-services is about to serve its agent over these routes, with
the Langfuse tracing and x-trace-id correlation its Chainlit host already
does. Without this the API would be the one surface in that deployment
producing no traces at all, and the alternative was forking POST /runs
downstream — a permanent divergence on the route most likely to change here.

🤖 Generated with Claude Code

create_router gains turn_context: a context manager entered inside the SSE
generator, given the request and both ids, yielding the turn's runnable
config. create_app forwards the same argument.

A context manager rather than a config factory because a tracing callback is
a value passed to the turn while a correlation id read by an httpx hook is a
context variable, which has to be set for the duration. Both need to be in
force while the turn runs, not while the handler is on the stack.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ciaransweet
ciaransweet merged commit 5474256 into main Aug 13, 2026
4 checks passed
@ciaransweet
ciaransweet deleted the feat/api-turn-context branch August 13, 2026 12:26
ciaransweet pushed a commit that referenced this pull request Aug 13, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.5.6](mcp-toolsets-runtime-v0.5.5...mcp-toolsets-runtime-v0.5.6)
(2026-08-13)


### Features

* **api:** a per-run hook for callbacks and context
([#79](#79))
([5474256](5474256))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: ds-release-bot[bot] <116609932+ds-release-bot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant