Skip to content

refactor: report read-only child configuration snapshots - #685

Merged
benbrandt merged 1 commit into
mainfrom
feat/subagent-configuration-snapshots
Oct 26, 2026
Merged

benbrandt merged 1 commit into
mainfrom
feat/subagent-configuration-snapshots

Conversation

@benbrandt

Copy link
Copy Markdown
Member

Summary

Step 7 of the incremental extraction tracked in #655, directly against current main after #684. This is read-only configuration reporting, not historical work outcomes or child controls.

  • Extend standard child configuration from model-only reports to complete reported model/reasoning-effort snapshots. Every select offers only its observed current value; neither parent values nor requested spawn arguments supply child values.
  • Preserve the existing model-source precedence and model labels. Newer observations remove unset/unavailable effort, including empty snapshots when no fields remain reportable. A model change cannot carry the previous model's effort.
  • Keep recorded configuration historical. Reattachment drops cached confirmation; fresh observations and verified, loaded provider metadata establish current configuration after the actual response write, including whole JSON-RPC batches.
  • Run optional metadata reads outside the notification lane and rejoin that lane only to publish. Newer observations, unload/close, or another attachment invalidate late results. Reads verify the physical child ID and immediate parent without loading or changing the child.
  • Ignore foreign runtime starts for history-only children; copied associations do not establish current configuration or ownership.

V1 standard opt-in, v2 defaults, empty child capabilities, mutation restrictions, and AIR's existing contract remain unchanged. AIR's only source change is exporting the existing source-priority constant for reuse. Dependencies and generated app-server types are untouched. Existing AIR and parent-session snapshots have no changes.

Review size

9 files, +653/-36 lines. About four fifths of the additions are tests/snapshots. Runtime changes stay within the standard router, its server wiring, and a small shared snapshot builder used by live and historical reporting.

Validation

  • npm run typecheck
  • npm test: 2,028 passed, 39 skipped. Includes 33 new v1/v2 wire regressions, with one v2-only batch case skipped on v1.
  • npm run build
  • npm run test:integration: 15 passed against real Codex 0.164.0 and a local mock Responses API. Native child tests now compare reported effort with the child's actual Responses request, both initially and after parent reattachment.
  • npm run bundle:all: all six platform targets compiled.
  • npm run codex-test -- -p 'Reply with exactly child-configuration-ok. Do not read files or use tools.' -c <isolated-scratch-directory> -o summary: live-model smoke completed with end_turn.
  • git diff --check

Wire tests cover complete singleton snapshots, effort-only/unknown/cleared values, model changes, source precedence and pre-announcement buffering, no-op mutation rejection, changed and unchanged reattachment snapshots, full and no-replay attachment, delayed batches, pending reads without blocked output, newer native settings, late reads across attachments/unload/close, untrusted metadata, and historical-only configuration.

The full live-model E2E suite was not run. Cross-platform bundles were compiled, not executed on each target OS.

Protocol / reference check

  • Specification main at 53620d0b325d6815b3cff1ca7e909351d488fdf0: RFD child configuration supplies the proposed child reporting, singleton-choice, and reattachment semantics. Existing draft configuration notifications require complete state in v1 and v2.
  • TypeScript SDK main at c7e07388feed7a530f8211d0dae4951cb6d26d09, with the installed SDK 2.0.2 used for real wire decoding/schema checks. SDK runtime evidence is separate from the specification; the existing actual-write response boundary and ordered session-transition helper are reused, not replaced.
  • Codex's generated Thread metadata documents model/effort as current configured values when loaded, or persisted values otherwise. Readback accepts only loaded, correctly parented children; persisted metadata alone does not confirm current configuration.

Historical work outcomes remain the next extraction. This PR does not merge or replace #655 wholesale.

@benbrandt benbrandt changed the title feat: report read-only child configuration snapshots refactor: report read-only child configuration snapshots Oct 26, 2026
@benbrandt
benbrandt merged commit 5bfffd3 into main Oct 26, 2026
7 checks passed
@benbrandt
benbrandt deleted the feat/subagent-configuration-snapshots branch October 26, 2026 14:35
benbrandt added a commit that referenced this pull request Oct 26, 2026
## Summary

Final planned extraction (step 8) from #655, directly against current
`main` after #685.

- Replay the **latest recorded child turn's** normal completion,
cancellation, or failure as historical `idle` before the load/resume
response, using the same stop-reason/error mapping as live turn endings.
- Emit no outcome for missing or still-running turn metadata. Do not
substitute an older completed turn for a latest running turn, or infer
endings from activity-item kind, missing content, or runtime loss.
- Reuse the legacy transcript's turn payload without a second full read.
Paginated history adds one optional latest-turn summary read (`limit:
1`, descending, no items); an unavailable summary retains available
transcript content and uses the existing history-gap advisory.
- Publish historical state directly, without changing the live
foreground cache, ending current interactions, establishing runtime
ownership, or enabling mutations. Parent closure fences late summaries.

V1 opt-in gating, v2 defaults, AIR behavior, current configuration
reporting, child identities, ancestry, and empty capabilities remain
unchanged. Dependencies and generated app-server types are untouched.
Existing AIR and parent-session golden transcripts are unchanged. Two
existing v2 child-replay snapshots gain the intended historical
`state_update`.

## Review size

15 files, +422/-22 lines. Most additions are tests/snapshots; runtime
changes touch only the history reader, standard replay dispatcher, and
standard child router. The router shares one explicit terminal-status
mapping between live and historical reporting, but historical
publication bypasses the live state cache.

## Validation

- `npm run typecheck`
- `npm test`: **2,064 passed**, 39 skipped, including **36 new v1/v2
outcome regressions**.
- `npm run build`
- `npm run test:integration`: **15 passed** with real Codex 0.164.0 and
a local mock Responses API. The v1/v2 completion cases now close the
parent and cold-load it before checking the recorded ending, avoiding a
cached live ending as a false positive.
- `npm run bundle:all`: all six targets compiled.
- `npm run codex-test -- -p 'Reply with exactly historical-outcomes-ok.
Do not read files or use tools.' -c <isolated-scratch-directory> -o
summary`: live-model smoke completed with `end_turn`.
- `git diff --check`

Wire regressions cover both history stores,
completion/cancellation/failure, unavailable or running final turns,
response ordering, no mutation/interrupt authority, independent
paginated summary failures, latest-turn selection, a subsequent
non-replaying resume, newer live permissions and actual work completion,
nested ancestry and repeated spawn records, late summaries after close,
and failures without details.

The full live-model E2E suite was not run. Cross-platform bundles were
compiled, not executed on each target OS.

## Specification / reference check

- Current specification `main`,
`5a5ab96ea8e0f6d3d5c5d7de3a7d29a87c79ddd2`: the [subagent RFD replay
rules and freshness
boundary](https://github.com/agentclientprotocol/agent-client-protocol/blob/5a5ab96ea8e0f6d3d5c5d7de3a7d29a87c79ddd2/docs/rfds/subagents.mdx#L724-L805)
distinguish historical pre-response state from confirmed current
activity and controls, and prohibit inventing outcomes from missing
history.
- The [explicit replayed-idle
clarification](https://github.com/agentclientprotocol/agent-client-protocol/blob/e839564daab1da2c68cb8a006c786dfcbf0e68f1/docs/rfds/subagents.mdx#L763-L809)
is still on the pending `rfd-replayed-subagent-outcomes` branch, **not
specification main**. It permits keeping a recorded idle outcome visible
without treating it as current activity or authorization. This
implementation is compatible with both versions and requires no new wire
fields.
- TypeScript SDK `main`, `c7e07388feed7a530f8211d0dae4951cb6d26d09`,
checked separately as reference/type evidence. Installed SDK **2.0.2**
performs real wire decoding in the regression tests; this change reuses
the existing v1/v2 state publication and actual response-write freshness
boundary.

This finishes the eight planned extraction scopes once merged; it does
not merge the old combined #655 wholesale. Child mutation controls and
directed-message extensions remain outside this work.
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