Skip to content

Commit a60a427

Browse files
authored
feat(subagent): single routing resolver with persisted binding provenance (#237)
## Related Issue No issue. Fifth step of the subagent routing work. Stacked on #236 (merge #234, #235, #236 first; until then this diff includes their commits). ## Problem Model selection for a new subagent lived in `planSpawn()` and again in `resolveSubagentBinding()`, and nothing recorded why a child was bound the way it was. A resumed child that kept an older model (created under "main = Luna", resumed under "main = Sol") was indistinguishable from a routing bug, and the Dynamic Workflow card had to guess. ## What changed - `resolveSubagentModelRoute()` is the single binding authority (inherit / default / pool / force; `primary` override; force rejects any explicit choice). `resolveSubagentBinding()` and the new `SessionSubagentRoutingService` both delegate to it. `planSpawn()` is a facade over the routing service; every plan carries `RoutingProvenance` (`operation`, `profileSource`, `modelSource`, `policyMode`, `policySource`, `featureSource`, `resolvedFromRoutingEnvironmentRevision`, `routeDecisionFingerprint`). - `SubagentBindingProvenance` is persisted once on the child (durable agent event `subagent.binding_provenance.recorded` folded into a replayable state key) when the child is created from a plan; forks record `fork-inherit`. Resume reads it back: sources become `resume-existing`, the original revision is kept, and the caller's current `routingEnvironmentRevision` is reported alongside — never written into the child. - Live path: `SubagentTaskInfo`, the `subagent.spawned` event, REST `/tasks`, the WS roster, and the session snapshot carry `routing` + `current_routing_env_revision`; `packages/protocol` schemas and the web client (`AppTask.routing`, `DynamicWorkflowMember`, card rows, `keepLiveSubagents`) map them. Stable enum ids only; no display labels on the wire. - Durable path: the Dynamic Workflow result writes `<subagent … profile model thinking profile_source model_source policy_mode policy_source feature_source routing_env_revision route_decision started_at completed_at>` through the existing attribute escaper; `parseDynamicWorkflowResult` reads them and older results still parse. - TUI: SDK types are additive/optional; `agent-dynamic-workflow-progress` and `subagent-event-handler` compile and their tests pass unchanged. - `dist-web` rebuilt; state and wire manifests regenerated. Tests: route matrix (inherit/default/pool/force × explicit/primary/none, force rejects `primary`); routing service provenance for spawn/pool/force/fork; two spawns share the environment revision and differ in decision fingerprint; the mandatory Luna→Sol resume regression (child stays on Luna, `resume-existing`, original revision A, current revision B); provenance recorded exactly once per child for spawn and fork; state fold + record guard; renderer attributes + escaping; gateway task mapping and roster tracker; web projector, mappers, parser (new attributes, old rows), card rows pass-through, task merge. ## Checklist - [x] I have read the [CONTRIBUTING](https://github.com/PyModel/pythinker-code/blob/main/CONTRIBUTING.md) document. - [ ] I have linked a related issue (external PRs: the issue must have a maintainer's `/approve`). - [x] I have added tests that prove my feature works. - [x] Ran `gen-changesets` skill, or this PR needs no changeset. - [x] Ran `gen-docs` skill, or this PR needs no doc update. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Subagent tasks and workflow results now display routing details, selected profile/model sources, policy decisions, environment revisions, and execution timestamps. * Routing information is preserved across spawned, forked, background, and resumed subagent runs. * Server metadata now exposes effective experimental feature-flag states. * **Bug Fixes** * Prevented routing metadata from being overwritten or lost when task data is merged. * Cleared stale suspension reasons when updated suspension events omit them. * Ensured secondary-model settings can be explicitly cleared when no longer available. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent faeb195 commit a60a427

138 files changed

Lines changed: 2309 additions & 536 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pymodel/pythinker-code": minor
3+
---
4+
5+
Subagent tasks and Dynamic Workflow results now record the profile, model, and routing source of each subagent, and a resumed subagent keeps the binding it was created with.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"sourceHash": "c3559f1b350b84cd73183ecca48c451946874033acb7af4738de205fdd4e4f7d",
2+
"sourceHash": "e6fc28927badd164b21beb1a6062a6469618d97c34e823eaea23cbbb24594b6d",
33
"sourceFileCount": 405
44
}

apps/pythinker-code/dist-web/assets/CodeBlockNode-DRvGmu0B.js renamed to apps/pythinker-code/dist-web/assets/CodeBlockNode-BWayTGpE.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/pythinker-code/dist-web/assets/DesignSystemView-CVU88etb.js renamed to apps/pythinker-code/dist-web/assets/DesignSystemView-U5edWnzl.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/pythinker-code/dist-web/assets/Tooltip-Dwp18XKI.js renamed to apps/pythinker-code/dist-web/assets/Tooltip-D-x_6nZf.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/pythinker-code/dist-web/assets/abnfDiagram-VCTEODGH-CpEdlyYv.js renamed to apps/pythinker-code/dist-web/assets/abnfDiagram-VCTEODGH-B5EIRmLW.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/pythinker-code/dist-web/assets/arc-C__I0s6O.js renamed to apps/pythinker-code/dist-web/assets/arc-ChDdl02F.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/pythinker-code/dist-web/assets/architectureDiagram-5GKGNRK7-D-HOppuj.js renamed to apps/pythinker-code/dist-web/assets/architectureDiagram-5GKGNRK7-Cu602jjl.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)