Skip to content

feat(agent): handoff routes, capability declaration, post-prompt normalization - #92

Merged
anthmFS merged 1 commit into
mainfrom
feat/agent-consolidation
Aug 13, 2026
Merged

feat(agent): handoff routes, capability declaration, post-prompt normalization#92
anthmFS merged 1 commit into
mainfrom
feat/agent-consolidation

Conversation

@anthmFS

@anthmFS anthmFS commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Adds HandoffRouter (the routes the SignalWire address widget already calls), capability declaration, and post-prompt normalization.

HandoffRouter

The address widget hardcodes {gateway-url}/handoff, /escalate and /say
against the same URL that serves a ChatGateway, and sends handoff_nonce and
chat_handle as user variables. Without these routes the SDK ships a gateway
its own widget considers incomplete, with the missing half specified nowhere.

It owns the wire contract only — routes, nonce, ordering guarantee, spend
guards — and nothing about what a conversation is; transcript capture and
resumed-greeting text are injected as callbacks.

The nonce is the load-bearing part. ai_message takes a call_id, so a
page-supplied one would let anyone who guessed an id inject speech into a
stranger's live call. The browser proves which call it is on instead: the
application puts a random handoff_nonce in one dial's user variables and the
browser presents it later. An unknown nonce is answered exactly like an expired
one, so it cannot be used to probe whether a call is live. Redemption is
single-use; typing is repeatable up to max_messages_per_call.

Plus core/capabilities.py and core/post_prompt.py, each with tests.

Verified against main's baseline, measured not asserted

  • 6060 tests pass, up 118. The 6 mcp_gateway failures are pre-existing and
    identical to main's.
  • mypy: 19 findings — the same 19 as main, set difference empty.
  • LINT and FMT clean.

Note

DRIFT reports new public surface here (core.capabilities,
core.post_prompt). Since #91 that is advisory — python is the reference and
the oracle is derived from it — so the snapshot gets regenerated downstream in
porting-sdk on its own schedule. ai_chat.handoff is excluded from that oracle
by porting-sdk#138 as Python-first, so it carries no cross-port obligation.

🤖 Generated with Claude Code

https://claude.ai/code/session_015dYktt85Ltj3oK9gG5VBww

…alization

Adds the second half of what a browser client needs around ChatGateway, plus
two pieces of agent infrastructure.

ai_chat/handoff.py — HandoffRouter. The SignalWire address widget already
hardcodes {gateway-url}/handoff, /escalate and /say against the same URL that
serves a ChatGateway, and sends handoff_nonce and chat_handle as user
variables. Without these routes the SDK ships a gateway its own widget
considers incomplete, with the missing half specified nowhere.

It owns the wire contract only — the routes, the nonce, the ordering
guarantee, the spend guards — and nothing about what a conversation is; where
a transcript is written and what a resumed greeting says are injected as
callbacks.

The nonce is the load-bearing part: ai_message takes a call_id, so a
page-supplied one would let anyone who guessed an id inject speech into a
stranger's live call. The browser proves which call it is on instead — the
application puts a random handoff_nonce in one dial's user variables and the
browser presents it later. An unknown nonce is answered exactly like an
expired one, so it cannot be used to probe whether a call is live. Redemption
is single-use; typing is repeatable up to max_messages_per_call.

core/capabilities.py, core/post_prompt.py — capability declaration and
post-prompt normalization, with tests for each.

Verified against main's baseline rather than asserted:
  - 6060 tests pass, up 118. The 6 mcp_gateway failures are pre-existing and
    byte-identical to main's.
  - mypy: 19 findings, the same 19 as main, set difference empty.
  - LINT and FMT clean.

DRIFT is the one gate this cannot satisfy from here: it adds public API, so
the surface oracle in porting-sdk needs regenerating, which a maintainer lands
alongside. Note porting-sdk#138 excludes ai_chat.handoff from the oracle as
Python-first (ChatGateway/HandoffRouter are route factories over AIChatClient
and add no server capability), so once that merges the regen covers
core.capabilities and core.post_prompt only.
@anthmFS
anthmFS merged commit 8253718 into main Aug 13, 2026
5 checks passed
@anthmFS
anthmFS deleted the feat/agent-consolidation branch August 13, 2026 23:26
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