feat(routing): session-routing plugin layer for per-session router affinity#15
Conversation
…finity One plugin category (session_routing) + one CLI flag (--session-routing <mode>, with repeatable --session-routing-opt key=value) covers every mechanism for telling an external router which session a request belongs to, so all of a conversation's turns re-land on the replica holding its KV prefix. "Session" (live instance keyed by x_correlation_id), not "conversation" (dataset template), is the affinity identity. Exactly one mode runs per invocation; the selected plugin is instantiated once per worker by InferenceClient and invoked at the request-serialization chokepoint. Built-in modes: - dynamo_headers (preset): X-Dynamo-Session-ID plus X-Dynamo-Parent-Session-ID on subagent children, for a Dynamo frontend running --router-session-affinity-ttl-secs. - dynamo_nvext: nvext.session_control request-body metadata -- bind (with timeout, option timeout_seconds, default 300) on every non-final turn, close on the final turn -- for Dynamo builds that implement session_control. Plugin values win over dataset-shipped session_control keys; other nvext content is preserved. - smg_routing_key (preset): X-SMG-Routing-Key for the SGLang Model Gateway manual policy. - session_id_header (preset): additive X-Session-ID, parameterless. - identity_headers: fully generic tiered identity headers emitting exactly what is configured, nothing by default. Options (each a comma-separable name list): session (this session's correlation ID), parent (immediate parent's ID, omitted for roots), root (session-tree root's ID -- whole-tree affinity, e.g. pinning an entire agent tree to one replica for prefix-cache locality). Requires at least one name across tiers; names are validated as RFC 9110 tokens at config time and must be case-insensitively unique across all tiers combined. Each header preset is documented with its identity_headers equivalent. Removed (superseded): --use-dynamo-conv-aware-routing / --use-dynamo-session-control, --use-legacy-dynamo-session-control, --dynamo-session-timeout-seconds, the dynamo_session_control module, AIPERF_HTTP_X_SESSION_ID_FROM_CORRELATION_ID, AIPERF_HTTP_X_SMG_ROUTING_KEY_FROM_CORRELATION_ID, and the base_transports env-toggle header blocks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Anthony Casagrande <acasagrande@nvidia.com>
Try out this PRQuick install: pip install --upgrade --force-reinstall git+https://github.com/ai-dynamo/aiperf.git@074a67d871eb3d7cd004ccde844cc2b34044dee8Recommended with virtual environment (using uv): uv venv --python 3.12 && source .venv/bin/activate
uv pip install --upgrade --force-reinstall git+https://github.com/ai-dynamo/aiperf.git@074a67d871eb3d7cd004ccde844cc2b34044dee8Last updated for commit: |
205b4dd to
1d17fd1
Compare
|
Added Same key selection as #14 — every session in an agent tree binds the tree root's correlation ID — with one refinement to the close discipline: instead of closing on the root conversation's own final turn (which can tear down the shared key while sibling subagents are still running), close fires only on a request the credit issuer stamped Verified with back-to-back
🤖 Generated with Claude Code |
Adds scope={conversation,lineage} to the dynamo_nvext mode
(--session-routing-opt scope=lineage; default conversation, unchanged
behavior). Under lineage, every session in an agent tree binds
nvext.session_control with the tree ROOT's correlation ID instead of its
own, so fork/spawn children co-locate on the worker (and data-parallel
rank) already holding the shared parent prefix -- an explicit client-side
affinity for Dynamo deployments without KV-event prefix indexing, where
an unbound child request is otherwise placed arbitrarily and re-prefills
the shared parent prefix once per child.
Close discipline: a shared affinity key must never be torn down while
sibling sessions may still run (a straggler's next bind would re-place it
arbitrarily and lose co-location), so under lineage the close fires only
on a request the credit issuer stamped is_tree_final -- provably the last
request of the whole tree, available under agentic replay, where the
has_branches gate guarantees a branch-declaring final turn never reads as
tree-final while children are pending. Under indeterminate modes
(reactive dag_jsonl) nothing closes and the session_control TTL reclaims
the key.
Lineage-scope design and motivation from SemiAnalysisAI#14
(YAMY1234), rebased onto the session-routing plugin layer: the flag
surface there (--dynamo-session-affinity-scope + EndpointDefaults +
EndpointInfo plumbing) collapses into this one Options field, and the
root-final-turn close is replaced by the is_tree_final discipline.
Verified with back-to-back --export-level raw mock-server runs of
--scenario inferencex-agentx-mvp against the PR ai-dynamo#14 implementation:
child binds are wire-identical (keyed on the tree-root ID in both), and
the lineage close fired exactly once -- on the provably-last wire request
of a fully-drained tree.
Co-Authored-By: YAMY1234 <yamy1234@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Anthony Casagrande <acasagrande@nvidia.com>
1d17fd1 to
074a67d
Compare
|
Converting to draft for now while I iron out a few details |
Summary
One plugin category (
session_routing) + one CLI flag (--session-routing <mode>, with repeatable--session-routing-opt key=value) covers every mechanism for telling an external router which session a request belongs to, so all of a conversation's turns re-land on the replica holding its KV prefix. "Session" (live instance keyed byx_correlation_id), not "conversation" (dataset template), is the affinity identity. Exactly one mode runs per invocation; the selected plugin is instantiated once per worker byInferenceClientand invoked at the request-serialization chokepoint.Built-in modes
dynamo_headers(preset) —X-Dynamo-Session-IDplusX-Dynamo-Parent-Session-IDon subagent children, for a Dynamo frontend running--router-session-affinity-ttl-secs.dynamo_nvext—nvext.session_controlrequest-body metadata:bind(with timeout, optiontimeout_seconds, default 300) on every non-final turn,closeon the final turn — for Dynamo builds that implementsession_control. Plugin values win over dataset-shippedsession_controlkeys; othernvextcontent is preserved.smg_routing_key(preset) —X-SMG-Routing-Keyfor the SGLang Model Gatewaymanualpolicy.session_id_header(preset) — additiveX-Session-ID, parameterless.identity_headers— fully generic tiered identity headers emitting exactly what is configured, nothing by default. Options (each a comma-separable name list):session(this session's correlation ID),parent(immediate parent's ID, omitted for roots),root(session-tree root's ID — whole-tree affinity, e.g. pinning an entire agent tree to one replica for prefix-cache locality). Requires at least one name across tiers; names are validated as RFC 9110 tokens at config time and must be case-insensitively unique across all tiers combined. Each header preset is documented with itsidentity_headersequivalent.Example commands
Removed (superseded)
--use-dynamo-conv-aware-routing/--use-dynamo-session-control,--use-legacy-dynamo-session-control,--dynamo-session-timeout-seconds, thedynamo_session_controlmodule,AIPERF_HTTP_X_SESSION_ID_FROM_CORRELATION_ID,AIPERF_HTTP_X_SMG_ROUTING_KEY_FROM_CORRELATION_ID, and thebase_transportsenv-toggle header blocks.Migration:
--use-dynamo-conv-aware-routing→--session-routing dynamo_nvext; the SMG env toggle →--session-routing smg_routing_key; the X-Session-ID env toggle →--session-routing session_id_header.Testing
session_id, header-modes-never-touch-the-body), plus live end-to-end runs of every mode.on_session_endnotify (positive and negative), capability flags and skip semantics, plugin-contract init rejections, credit finality stamping at allTurnToSendseams, PAYLOAD_BYTES gates (preformat bail, format selection, cache-hit downgrade and its lookup-site wiring, cache-population skip), and theidentity_headerstier/validation matrix.cquil11/aiperf-agentx-v1.0before this branch).🤖 Generated with Claude Code