Repository navigation
refactor(native-chat): structured agents declare their capabilities instead of shared code naming Claude and Codex - #25076
Conversation
…ed code
Shared structured-chat code parsed each provider's resume handle: Claude's
session id and branch leaf, Codex's thread id, through a 'claude' | 'codex'
union every new agent had to widen. The in-memory handle is now
{ transport, agent, nativeId, providerData? }: shared readers use nativeId,
lease and handle-chain checks compare transport and agent, and only the
Claude adapter reads its leaf (providerData).
Stored and wire forms are unchanged for Claude and Codex. One encoding
module writes their typed shapes and decodes both those and the neutral
shape a new transport uses, which an older build refuses as unreadable
rather than reading as Codex. Key and root strings, which fork seeds,
superseded creations and resume offers persist, stay byte-identical.
The journal's own handle type becomes the journal-row and attach-wire
encoding of the same handle, and the journal identity carries the
neutral handle (null before the provider proves one).
No user-visible change.
…l identity The journal row converter now takes the identity every caller already holds, so a row's handle has one obvious constructor. Tests that wrote the in-memory handle straight into journal rows now build it through that converter, and the processless Claude fixture names a not-yet-proved handle as null.
A typed Claude or Codex handle that also carries the neutral form's transport, agent, native id or provider data named two identities; it was read as Claude or Codex and the next write dropped the other one. Such a row now stays unreadable and is set aside untouched.
…initions The structured-chat shared layer named Claude and Codex in a closed router type, in option reads, in frame classification, and in renderer label and validation branches, so adding an agent meant editing shared types. Each agent now has a definition (capabilities, resting option rules) owned by its own module; the router is a registry of definition + adapter pairs built at runtime setup, and shared code reads the definition instead of the name. No behavior change for Claude or Codex; no wire or stored shape change.
The host types, conversation commands, provider-session ownership and the runtime's create path spelled the structured agent list inline; they now use the one shared type the record and wire already validate against.
…gent-registry # Conflicts: # src/renderer/src/lib/structured-agent-session-provisional-tab.ts
… definition lookup The at-rest option reads looked definitions up in a second, separately populated map, so a registered definition could route and declare capabilities while the static map decided which options a chat at rest accepted. The router now answers `definition(agent)` from its registrations, the at-rest readers take it through the host's adapter, and the built-in definitions are listed only where the runtime composes the router.
…n suite Main grew the suite to the 800-line limit; the opaque-handle import pushed it over. The two tests built the same identity inline.
Rename the neutral provider handle's providerData to resumeCursor before any row persists the neutral form: it is an adapter-owned resume position (Claude's transcript leaf), never identity. Claude/Codex stored and wire bytes are unchanged; their typed shapes never carried the field. State the stored-form contract (a handle's field set is closed; later per-link data goes on the chain link, which every build preserves) and pin it with a record round-trip test. Document that transport records the id space the native id was minted in, which can differ from the agent's current transport.
…e' into brennanb2025/acp-a2-agent-registry # Conflicts: # src/renderer/src/lib/structured-agent-session-provisional-tab.ts
…mit what they claim
A StructuredAgentRegistry, built once from the {definition, adapter}
registrations, is now a required host dependency and the router routes with
it. The adapter interface loses its optional router-only capabilities?() and
definition?(); every reader (options at rest, thread goal, rewind, the
/compact handover) asks the registry. A live session still narrows rewind
through the adapter, and the host combines declared and narrowed in one
helper. The registry refuses a registration that declares compact, a thread
goal or rewind without the adapter method behind it.
/compact is admitted by the declared capability, so an agent that declares
compact:false gets the commandRefused fact instead of a thrown error.
Also: the cut-turn notice names the agent from the catalog, create-support
builds the account home through agentSessionAccountHome, and the turn
status text older clients read names the session's agent instead of
defaulting to Codex (Claude/Codex text unchanged).
The router holds the registry, so its rewindSupport answers the owner's declared rewind narrowed by the adapter, in one place no reader can bypass. The host-side combining helper is gone; readers ask the adapter they hold.
…nly empty capability record
Review summary (head
|
main #24576 deleted agent-session-journal-recovery.ts and its two tests; take the deletion (this branch only re-pointed them at the neutral provider handle). Main's new journal and cross-version tests build journal identities with codexProviderHandle(); the older-build open in the newer-chat cross-version test keeps the legacy handle shape it reads.
main #24576 removed historyFilePath from the structured adapter interface; drop this branch's registry-routed copy in the adapter router. Main's new host and turn tests (newer-content-host, unopened-tab, stop-note-withdrawn-send) pass the agent registry this branch made required.
- claude-unproven-stop-send.test.ts: deleted on main (replaced by claude-stop-exit-ends-record); take the deletion. The replacement builds its host with claudeAndCodexAgents(adapter), as the deleted test did here. - codex-stop-row.test.ts: this branch's agents dep + main's recording logger.
|
Merged current main into this branch twice (now
|
… A4/A5/B1) The conflicts were all "A2's copy of A1" against main's squash of A1. Resolved by re-merging with old-main+A1 as the base, so the result is main plus exactly A2's own change.
…d-turn test Main's #25706 and this branch both added the import at different lines; the merge kept both.
|
Earlier CI merges missed main's restored provider-handle import and the test-only parser dependency still needed by old release checkouts. Merged main |
📝 WalkthroughWalkthroughThe change introduces registry-backed structured-agent definitions and routes session operations through registered adapters. Agent capabilities and resting-option rules now come from definitions. Shared account-home helpers replace provider-specific variable handling in affected APIs. Renderer and legacy status text use agent identity and display names more directly. Test hosts now receive explicit agent registries. Priority: ⬇️ Low Merge Risk: 🔵 Low · up to The remaining test-fixture cleanup does not block merging; the test checks the intended behavior. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change centralizes security-sensitive routing and operation eligibility. Inspected controls remain in place, but incomplete coverage of identity and permission boundaries leaves limited residual uncertainty. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❓ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 45.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 50 files. (80 skipped: 80 over the file limit.) ✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/native-chat/agent-session-wire/structured-agent-session-mutation-owed-import.test.ts (1)
93-96: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueRemove the unused adapter
capabilitiesstub.The test host already uses
claudeAndCodexDeclared().performThreadGoalChangechecksctx.agents.capabilities(ctx.agent), not an adapter property. The stub does not enable the goal path and misstates where capability declarations come from.Suggested cleanup
-import { CODEX_STRUCTURED_AGENT } from '../../codex/codex-structured-agent-definition' ... Object.assign(host.deps.adapter, { - changeThreadGoal, - capabilities: () => CODEX_STRUCTURED_AGENT.capabilities + changeThreadGoal })
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
87506e7a-89f9-4c92-a357-94b0a08fd4a6
📒 Files selected for processing (132)
src/main/claude/claude-api-retry-idle-sweep.test.tssrc/main/claude/claude-context-usage-unloaded-turn.test.tssrc/main/claude/claude-structured-agent-definition.tssrc/main/claude/claude-structured-effort-default-at-rest.test.tssrc/main/claude/claude-structured-launch-resolution.tssrc/main/claude/claude-structured-session-adapter.tssrc/main/claude/claude-structured-session-test-support.tssrc/main/codex/codex-provider-retry-idle-sweep.test.tssrc/main/codex/codex-structured-agent-definition.tssrc/main/codex/codex-structured-launch-resolution.tssrc/main/codex/codex-structured-question-order.test.tssrc/main/codex/codex-structured-session-adapter.tssrc/main/codex/codex-structured-session-close.test.tssrc/main/native-chat/agent-model-catalog/agent-model-catalog-fingerprint.tssrc/main/native-chat/agent-model-catalog/agent-model-catalog-service.tssrc/main/native-chat/agent-session-wire/provider-frame-disposition.tssrc/main/native-chat/agent-session-wire/structured-agent-definition.tssrc/main/native-chat/agent-session-wire/structured-agent-registry.tssrc/main/native-chat/agent-session-wire/structured-agent-session-accept-then-deliver.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-router-registry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter-router.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adapter.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adopted-import.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-append-delivery.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-at-rest-commands.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-compact-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-echo-working.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-option-queue.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-queued-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-root-exit.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-ends-session.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-exit-ends-record.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-turn-end.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-close-verdict.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-row.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-command-turn.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-crash-mid-start.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-crash-turn-end.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-delivery-loop.tssrc/main/native-chat/agent-session-wire/structured-agent-session-failed-create-owner-verdict.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-failed-create-sink-release.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-grouped-prompt.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-delivery.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-mutations.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-test-abandon.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-test-harness.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-types.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-import-mismatch.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-late-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-legacy-handoff-record.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-main-agent-working-agreement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-admission.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-context.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-owed-import.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-turn-context.tssrc/main/native-chat/agent-session-wire/structured-agent-session-newer-content-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-operation-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-operation-start-refusal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-option-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-options-read.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-options-read.tssrc/main/native-chat/agent-session-wire/structured-agent-session-owed-work-release.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-child-record.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-restore.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-started.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-support.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-recovery-exits.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-refusal-retry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-registered-definition.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-repeat-press.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-repeated-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rest-test-rig.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-interruption-test-harness.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-status-publication.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind-at-rest.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-idempotency.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-open-stale-turn.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-restarts-failed-start.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-settled-attach-retry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-start-failure-writer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-startup-reconcile-failure.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-note-opened-turn.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-stop-note-withdrawn-send.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-surface-lifetime.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-thread-goal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-thread-goal.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turns.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turns.tssrc/main/native-chat/agent-session-wire/structured-agent-session-unopened-tab.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-view-start-after-failed-start.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-wedged-profile-migration.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-command.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-command.tssrc/main/native-chat/agent-session-wire/structured-conversation-compaction.test.tssrc/main/native-chat/agent-session-wire/structured-provider-session-ownership.tssrc/main/runtime/orca-runtime-get-structured-agent-session-create-support.tssrc/main/runtime/rpc/methods/structured-agent-session-adoption-replay.test.tssrc/main/runtime/rpc/methods/structured-agent-session-at-rest.test.tssrc/main/runtime/rpc/methods/structured-agent-session-hold.test.tssrc/main/runtime/rpc/methods/structured-chat-tab-table.test.tssrc/main/runtime/structured-agent-session-runtime.tssrc/main/runtime/structured-claude-pending-rewind.test.tssrc/renderer/src/components/native-chat/NativeChatStructuredSession.tsxsrc/renderer/src/components/native-chat/use-host-model-catalog-upgrade.tssrc/renderer/src/components/native-chat/use-structured-agent-session-options.tssrc/renderer/src/components/native-chat/use-structured-agent-session.cut-turn-notice.test.tsxsrc/renderer/src/components/native-chat/use-structured-agent-session.tssrc/renderer/src/lib/structured-agent-session-launch-label.tssrc/renderer/src/lib/structured-agent-session-launch-persistence.tssrc/renderer/src/lib/structured-agent-session-provisional-tab.tssrc/shared/agent-session-account-home.test.tssrc/shared/agent-session-account-home.tssrc/shared/agent-session-capabilities.tssrc/shared/agent-session-option-catalog-claude-codex.tssrc/shared/agent-session-option-catalog-types.tssrc/shared/agent-session-record.tssrc/shared/agent-session-turn-record.test.tssrc/shared/agent-session-turn-record.tssrc/shared/agent-turn-lifecycle-text.tssrc/shared/structured-agent-session-mutation.tssrc/shared/tui-agent-display-names.tstests/e2e/cross-version-wire/cross-version-agent-session-wire.unit.test.tstests/e2e/structured-chat-owner-status-activation.unit.test.ts
💤 Files with no reviewable changes (2)
- src/main/codex/codex-structured-session-adapter.ts
- src/main/claude/claude-structured-session-adapter.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.
ELI5
Orca's structured native chat (the chat view that drives an agent through its own protocol instead of scraping a terminal) only knows two agents, Claude and Codex, and that fact was spelled out in many places of the shared code: "if the agent is Codex do this, else assume Claude". Adding a third agent meant editing all of those places. This PR gives each agent a single description of itself (what it can do, and how its options behave while no chat is running) and makes the shared code read that description instead of asking "is this Claude or Codex?".
There is no user-visible change: Claude and Codex chats behave exactly as before.
What Changed
The problem. Before this PR:
{ claude, codex }, so a new backend was a type edit, not a registration.compactmethod always existed, so "can compact" was true for any agent.=== 'claude'/=== 'codex'branches. Some defaulted silently: the chat header label wasagent === 'codex' ? 'codex' : 'claude', so any other agent would have been called Claude.'CLAUDE_CONFIG_DIR' | 'CODEX_HOME'inline.Mechanism now.
StructuredAgentDefinition): each agent's own module declares one (claude-structured-agent-definition.ts,codex-structured-agent-definition.ts): its capability record and its at-rest option rules (which option keys it accepts, its fallback model list, whether an unpicked effort means "the model's default").AgentSessionCapabilities, plain JSON insrc/sharedso the next PR can send it to clients unchanged):rewind,compact,threadGoal,contextUsage,imagePrompts,steering: 'inject' | 'queue',approvalEnforcement: 'provider' | 'orca'. The values reproduce today's behavior exactly (a test pins them). A running chat may narrow a declared capability, never widen it: Codex rewind is still narrowed to unsupported for a thread with legacy history.StructuredAgentRegistry,structured-agent-registry.ts): built once at runtime setup from the{ definition, adapter }registrations, and a required dependency of both the host and the router. It answersdefinition(agent),definitions()andcapabilities(agent). It refuses a duplicate registration, and a registration whose definition declarescompact,threadGoalorrewindwithout the adapter method that does it, so a declaration can't drift from what the adapter can do. Every reader asks it: option reads at rest (which options a stopped chat accepts, its fallback model list, its default effort), compact admission, thread goal and rewind. There is no second map of agents: Claude's and Codex's definitions are listed only where the runtime builds the registry, so a definition the runtime did not register cannot affect any read.supportsThreadGoal/recordsContextUsagemethods and the "method exists" checks are gone, and so are the adapters' own copies of those answers. A running chat may only narrow: the router'srewindSupportapplies the declaredrewinditself and then the adapter's narrowing, so no caller can widen it./compactis admitted by the agent's declaredcompactcapability (before, the router's always-presentcompactmethod admitted it for any agent). An agent that declares no compaction gets the existing "command refused" answer.message:resultrule moved into Claude's entry. (This is still a third per-agent table beside the definition; see the temporary list.)src/shared/agent-session-account-home.tsowns the concept (the environment variable that points an agent at its config directory). Stored values are byte-identical ({"variable":"CODEX_HOME","path":…}); the stored-record check still admits only a variable some agent declares, because that variable becomes a child process's environment. The Claude and Codex launch checks and the model-catalog fingerprint read it from there.=== 'claude' ? 'Claude' : 'Codex'. Claude and Codex text is byte-identical; a row with no record and nolegacy:id would now say "Agent" instead of guessing "Codex", which no real chat reaches because the record store never deletes records.hostListingNamesConfiguredModel) instead ofagent === 'codex'.structured-agent-session-provider-support.ts): the fallback no longer assumes such an adapter is Codex. In production the host always holds the router, which has a per-agent check, so this only affects single-adapter test doubles.Deliberately left as Claude/Codex lists (each one place, not a branch):
AGENT_SESSION_PROVIDER_HANDLE_PROVIDERS/AgentSessionHandleProvider: what stored records, RPC params (including the account-home variable enum) and persisted tab state validate against. Widening it is a wire and stored-data change, which feat(native-chat): open structured chat's wire and stored records to registered agents, behind a negotiated capability #25159 does behind a new host capability (agent-session.structured.registered-agents.v1). temporaryagent-session-account-home.ts(which environment variable points each agent at its config directory). It is not derived from the registered definitions yet because its one safety-relevant reader is the stored-record check (isPersistedAgentSessionRecord), a pure shared function that the record store runs while loading rows, before any adapter or router exists. That same check still hard-codes the stored agent list itself (claude | codex). Making it read the registrations means passing the runtime's declared variables into record loading, which belongs with widening that stored agent list. temporary: the next PR, which widens the stored agent list behind a host capability, and the protocol-agent launch description, which declares the variable with the agent, move both checks onto the registered definitions.agent-model-catalog-*) still types its agent as Claude/Codex: it is probe infrastructure that gets an agent-neutral shape when the first protocol-driven agent reports its own model list. temporary: feat(native-chat): open structured chat's wire and stored records to registered agents, behind a negotiated capability #25159 opens its types to any registered agent.orca-runtime-get-structured-agent-session-create-support.ts; the location gate picks Claude's or Codex's rule by name because the agent picker asks before the registry exists). temporary: feat(native-chat): open structured chat's wire and stored records to registered agents, behind a negotiated capability #25159 moves account resolution and location support onto each agent's runtime registration (which exists before the host starts), with Claude and Codex as ordinary entries.provider-frame-disposition.ts): classification belongs to the protocol (every ACP agent shares one) or to the definition. temporary: an agent without an entry gets the safe default (its frames stay visible), which is what the ACP adapter PR (feat(native-chat): Grok as a structured chat over the Agent Client Protocol #25225) relies on; moving classification onto the definition or the protocol is a follow-up.structured-agent-session-create-adoption.ts) stays Claude/Codex: only they have transcript importers. intended for now.use-native-chat-session-options.tsand the option discovery files is a different chat system and out of scope.Why
Adding an agent should be "write its adapter and its definition, register it", not a sweep through shared types, and a client should be able to learn what an agent supports before a chat runs. A capability record declared per agent and narrowed by the running session is the common pattern: a static declaration readers use instead of the agent's name, with the live session allowed to narrow it but never widen it.
Alternatives considered:
src/sharedso the renderer can read it directly. Rejected: clients must learn capabilities from the host they talk to (an older or remote host may differ), which the next PR does by publishing this same record. Only the account-home variable table is shared, because the stored-record check needs it.variableany environment-variable name. Rejected: the stored variable is set on a child process, so it stays limited to names an agent declares.Differences from the common pattern
imagePrompts,steeringandapprovalEnforcementare declared, but nothing in this PR reads them. temporary: feat(native-chat): Grok as a structured chat over the Agent Client Protocol #25225 readsimagePrompts; nothing in the current stack readssteeringorapprovalEnforcementyet. They stay so the published record (feat(native-chat): open structured chat's wire and stored records to registered agents, behind a negotiated capability #25159) already says how a protocol agent's follow-ups and permission requests are handled. For protocol-driven agentsapprovalEnforcementwill beorca: Orca answers every permission request the agent sends, by the session's setting. The agent's own settings still decide when it asks, soorcanever means a sandbox.Linked Issue
N/A (internal stack: native chat for more agents).
Visual Proof
N/A: no user-visible change; labels resolve from the same catalog entries as before.
CI status (October 5)
Merged current main. On head
288f72cd43bevery CI check passes: typecheck, static analysis, all five unit-test shards, cross-version wire compatibility, relay integration, and packaging for macOS and Windows.Testing
What I verified:
structured-agent-session-registered-definition.test.ts: a router registered with non-default Claude rules routes to its adapter, answers that registration's capabilities, accepts that registration's option keys at rest (and refusesmodel, which Claude's own module accepts), and reads that registration's fallback models and default effort. A router that did not register Claude refuses its option picks and reads no rules for it, even though this build ships Claude's definition. A pick for a session with no record is refused, as before.orca-runtime.test.tsand the runtime's other suites (59 files): all pass.oxlint/oxfmtclean on changed files.What I didn't verify:
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)