Skip to content

Admit one provider event's journal writes as one queued operation, decided when it runs - #25141

Merged
brennanb2025 merged 18 commits into
mainfrom
brennanb2025/acp-c1a-timeline-transitions
Oct 6, 2026
Merged

brennanb2025 merged 18 commits into
mainfrom
brennanb2025/acp-c1a-timeline-transitions

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​520 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​520
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​389 $\color{#cf222e}{\Huge{\mathbf{−}}}$​83 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​306

ELI5

In a structured chat, Orca writes everything an agent does as rows in the chat's history, called the journal: the agent's reply, each tool call, each approval prompt, and one row per turn. Today Claude and Codex each have their own translator that writes those rows. The next PR, #25064 (stacked on this one), will add one shared timeline assembler that writes the rows for new agents, starting with Grok.

That assembler will need something the journal can't give it yet. One event from an agent (for example, "this turn ended") often needs several rows: the turn row, plus closing every tool call still open in it. Writes go through a bounded queue (the event sink) that can refuse work when it is full. If the queue took the first two writes and refused the third, the assembler's memory ("I ended that turn") and the journal (the turn still looks open) would disagree.

This PR adds the small pieces that let one event's writes be accepted or refused as a single unit, with each write decided against the journal at the moment it runs. Nothing uses them yet, so there is no user-visible change.

What Changed

User-facing change: none. Nothing new is wired into an agent, a client, or the runtime.

The mechanism:

  1. A transition: one event's writes as one queued operation (structured-agent-session-transition.ts, new). The event sink gains tryAppendTransition. All the rows one event writes enter the sink's queue as one operation, so the queue accepts the whole operation or refuses it whole. When it runs, its steps are written back to back, so no other write lands between them. Each step reads the journal as it stands at that moment, including the rows the steps before it just wrote. That way the journal decides what a step writes, not the assembler's memory, which can be stale (another writer, such as a person pressing Stop, may have changed the row since).

    • Accepted whole, written as a prefix. A refused operation writes nothing. An accepted one writes its steps in order until one fails. When a step fails, the steps before it stay written, the steps after it write nothing, and the sink fails. A failed sink accepts nothing more, and the session reports the failure the way it already does for any failed journal write. A step can fail in several ways: a database error, a row larger than the step reserved, the step's own code throwing, a settlement that names one item twice (see 2), or a read-only journal.
    • All steps run as one turn in the journal's write queue (journal-step-writer.ts, new; the journal's appendSteps). The journal runs its queued writes one at a time. A transition is one of those writes, and its body is a loop over the steps. Each step does what main's multi-row write already does (check the journal is writable, choose the rows, build them, insert them in their own database transaction, apply them to the in-memory view of the journal); that part is split out of enqueueRows as writeRows, and enqueueRows now just queues it, so its existing callers behave exactly as before. The loop stops at the first step that throws and passes that error on. So "the steps after a failure never run" and "no other write lands between the steps" hold because of how the code is shaped, not because a later step infers what happened before it. A write issued while the steps run, even from inside a step's own code, waits until the whole transition is done.
    • Events accepted before a failure still land. This is the sink's existing rule, unchanged here: a failure stops the sink from accepting anything new, but an event it had already accepted before the failure was known is still written. A writer that needs two things to happen together (for example, close one turn and open the next) must put both in one transition.
    • The sink also exposes the bound journal read-only (journalItems), and the journal gains item(id): one row with the turn it belongs to.
  2. A settlement chosen when it runs (journal-lifecycle-batch-appender.ts, journal-store.ts). A settlement is the batch of rows that closes out what a turn or session left open (running tool calls, pending prompts). A settlement step picks those rows from the journal at its turn in the queue, not when it was planned (planResolved on the settlement writer). A settlement too large for one row is split into consecutive rows, and all of them commit in one database transaction through writeRows, the body of main's all-or-nothing enqueueRows (the multi-row write added on main in fix(native-chat): show a message Orca accepted and then failed to deliver as "Not sent" in the chat #24710). Every row is built before any commits, so a settlement that names the same item twice is refused before anything is written. Otherwise the second row would reuse the first row's revision number.

  3. Streamed text that a caller writes itself (agent-session-delta-coalescer.ts). The helper that batches streamed text gains dirty() (streams with text not written yet) and markFlushed(key) (the caller wrote it). The assembler will use them to put pending text inside a transition instead of letting the helper write it separately.

  4. The turn-row writer moves to shared code (claude/claude-turn-row-revision.ts → native-chat/agent-session-timeline/agent-journal-turn-row-revision.ts). This is more than a rename, so here is all of it:

    • Claude's turn-row revision writer moves and drops "Claude" from its names. Claude's two callers change only their imports.
    • Its row-choosing logic is extracted, unchanged, into two exported functions, agentJournalTurnRowReservedBytes and resolveAgentJournalTurnRowWrite, so a transition step can reuse it.
    • It gains one option, onlyWhileRunning: write only while the turn row is absent or still running, so an ended turn is never reopened. Claude doesn't set it, so Claude's behavior is unchanged.

Why

The shared assembler must never act on memory the journal can contradict. Deciding each write against the journal when it runs, and admitting one event's writes as a single unit, gives it exactly that. It needs no new durable state.

What an earlier version of this PR had, and why it is gone. The first version also added a new optional field on journal rows holding the agent's own id for the item (a "provider item reference"). It also added an index that re-found rows by that reference after a restart, per-agent id-spelling schemes, and a counter for message positions within a turn. These defended one situation: the assembler loses its memory while the same agent process keeps writing the same turn. Nothing in production reaches that situation. The assembler lives exactly as long as the agent process it translates. After a restart, a new process starts, and Orca's existing startup cleanup settles whatever the old one left open. The Codex id the field would have stored was also unstable: Codex renumbers its item ids when a conversation resumes. A field persisted in users' data forever, defending an unreachable state with an unstable value, is worse than none. So the field, the index, the schemes, the cross-version test for the field, and the move of Codex's message counter are all removed. If Codex later moves onto the assembler and proves it needs a stored reference, that work adds it with its own evidence. Also removed, because nothing planned uses them: the earlier version's row-by-row settlement writer, a callback reporting which steps wrote, a flag that let a step skip its size check, and a way for a step to replace the row placement it was planned with.

Alternatives considered:

  • Write each row as its own queued operation (today's pattern for single writes). Rejected: a refusal in the middle of an event leaves the assembler and the journal disagreeing, which is the bug this PR prevents.
  • Decide every row when the event arrives and queue fixed rows. Rejected: another writer (a person's Stop, a client answering a prompt, the startup cleanup) can change the row between planning and writing, so a fixed row could reopen what they closed.
  • Write a large settlement row by row (each row committed alone). Rejected: a failure between rows would leave half a settlement durable. One transaction is simpler, and main already has it.
  • Write all of one event's steps in one database transaction. Rejected: rows in one transaction are all built before any commits, so a later step could not read what an earlier step wrote, and each step must read the journal as it stands.
  • Stop later steps by waiting for each step's result before issuing the next. Rejected: other writes could then land between the steps of one event.
  • Queue each step as its own write and have a later step check whether the one ahead of it completed (an earlier version of this PR: a count of completed writes on the journal's queue, read by each step). Rejected: it worked, but only by inference. It added a counter to main's write queue, needed a special case for a step that writes nothing, and needed every step to settle before the failure was reported. It also relied on no step's own code issuing a write: such a write would have landed between two steps and could hide a failure from the next one. One queued write that loops over the steps gives the same result with none of that.

Differences from the common pattern

  • Writes are decided when they run, not when the event arrives. Intended: Orca's sink queues work, and several writers share one chat's journal (the agent, a person's Stop, clients answering prompts, startup cleanup). The common pattern has one writer per timeline, so plan time and write time can't disagree there. Here the journal stays the authority on facts other writers own.
  • One event's writes are accepted as a unit but written as consecutive writes, stopping at the first failure. Intended: a refusal, the case that happens under normal load, writes nothing. A failure after acceptance (a database error, an oversized row, a throwing step, a settlement naming an item twice) leaves only the steps before it written, each a complete row, and fails the sink, so nothing more is accepted. The rows before the failure are not announced by this operation; the session's existing failure handling takes over from there.
  • Settlement is written as rows when a turn ends, rather than derived when history is read. Intended: Orca's clients read the journal's rows directly and do not compute settled state themselves. This PR only adds the write. The assembler PR will decide when to call it.

Linked Issue

N/A (maintainer). Part of the work to give agents beyond Claude and Codex a structured native chat. #25064 (the assembler) is stacked on this PR.

Visual Proof

N/A: no UI or behavior change. Nothing is wired.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

What I verified:

  • structured-agent-session-transition.test.ts (14 tests): steps land back to back, each reading the one before it; a refused transition writes nothing; a failed last step keeps the steps before it, fails the sink, publishes nothing, and the sink refuses later work; in a three-step transition whose middle step fails, the third step writes nothing, for each of three failures: the middle row is larger than it reserved (the third step's code is never called), the middle settlement names an item twice (the earlier tool call stays running and no next-turn row appears), and the database refuses the middle row; a settlement too large for one row lands as consecutive rows from the journal as it stands; a settlement whose second row's insert fails inside the transaction leaves neither row durable; a settlement naming one item twice is refused before writing; nothing written means nothing announced; a write a step's own code issues lands after the whole transition, not between its steps; a transition waiting behind a chat's not-yet-copied history (the copy runs before the chat's next write, so writes wait in line) still runs its steps back to back, ahead of a write issued after it; in that same waiting case, a failed middle step stops the third, and a write the sink accepted before the failure still lands; the text helper's dirty/markFlushed.
  • I checked that the tests fail without the loop's design. With the loop changed to keep going after a failed step, the three middle-step tests and the waiting-in-line failure test fail (the third row lands). With each step queued as its own write instead of one loop, those four fail and so does the write-from-inside-a-step test (that write lands between the steps). Earlier I checked that the two settlement tests fail with each settlement row committed alone.
  • 23 test files, 248 tests pass, including main's suites for the journal's write queue, the row writer, a crash between writes, the chat-history copy that runs before the first write, the all-or-nothing multi-row write (fix(native-chat): show a message Orca accepted and then failed to deliver as "Not sent" in the chat #24710), the send receipt that commits with its row (A resent chat message gets its recorded answer, never an early refusal or a made-up record #25158), the journal store, the sink and its resolved single-row write, the text helper, dead-generation settlement, and Claude context usage.
  • oxlint and oxfmt pass on every changed file. No max-lines exception.
  • Typecheck (node project): one gated local run at ff089865ceb (this branch with current main merged in). Its only errors are 5 missing stream-json/stream-chain module paths from this machine's stale shared install, in files this PR does not touch. CI is the authority.
  • CI status at ff089865ceb: "static analysis and typecheck" passes, including lint, the full typecheck and the localization extraction, catalog and coverage checks. The localization-coverage and editor-test typecheck failures main had earlier on 10-05 are fixed on main and no longer affect this branch.

What I did not verify:

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Security: no new input surface.
  • Cross-platform: no platform-specific code.
  • SSH and remote: no wire or row-shape change. Nothing resolves on the local machine, and nothing imports Electron.
  • Mobile: no mobile impact. Nothing the mobile app reads changes.
  • Backwards compatibility: no new row field or row kind. Journals written by this build read the same on older builds.
  • Performance: a settlement reads the rows it settles once, when it runs. No new scans on the write path.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred). Locally: oxlint on the changed files, the node typecheck above, and the 23 suites above. CI covers the full runs.

…al timeline folder

Pure moves so a shared timeline assembler can use them: Codex's message
ordinal counter becomes ProviderTurnMessageOrdinals and Claude's turn-row
revision becomes the provider-neutral agent-journal turn-row revision. Only
names and import paths change.
…found again after a restart

- A sink transition is admitted whole or not at all; its steps run back to
  back at their turn in the journal's write queue, and each resolver reads
  the fold with every earlier write landed. A resolver may also say where the
  row belongs (turn scope, provider reference), and the writer always hears
  how the transition landed. A resolved lifecycle batch chooses its
  settlement mutations from the fold at execution.
- New optional row field providerItemRef: the provider's own reference for
  the item a row is, written only where the row's identity cannot spell it
  (Codex keys messages by their place in the turn and renumbers its item ids
  on resume). Set by the creating write, kept by revisions, indexed by the
  journal fold, never read by clients. A downgrade test shows an older host
  and client render such rows unchanged.
- Provider timeline identity schemes (shared legacy arm, Codex) and the join
  index that resolves a provider item to its row from memory or the fold:
  ordinals and request incarnations are read back from the rows, so a
  restart or an evicted entry finds the original row instead of placing a
  new one.
… joins read from a replaced epoch

A fresh join index continued a turn's messages at the first free place, so a journal holding only a
later ordinal (an imported or removed earlier row) had its sequence back-filled. The place is now
one past the highest ordinal any row or echoed send holds there, read through a pure scheme reader.
The join caches also drop what they read when the journal's epoch is replaced.
Keeps both multi-row writes: the transition's per-row write (each built after the
one before it folds) and main's all-or-nothing queued-rejection write. Main's
ledger receipt rides the shared single-row write. A resolved lifecycle batch
cannot carry rejectsQueued, so it is never silently dropped.
…m the transition PR

Nothing in production reaches the state they defended (an assembler that lost its memory while
its child keeps streaming the same turn), and the stored Codex id was positional. The legacy
identity scheme moves to the assembler PR with its first caller; the Codex scheme and any
persisted reference wait for Codex to move onto the assembler. The Codex ordinal counter goes
back to codex/, since no neutral code imports it.
A settlement too large for one row now commits all its rows or none, through the journal's
existing all-or-nothing write, instead of a row-by-row writer. Every row is built before any
commits, so a settlement naming one item twice is refused before anything is written.
…d-forget

Nothing reads which steps of a transition wrote. A failed step fails the sink, leaving the
steps before it written; the header says so, and tests cover it plus a settlement whose second
row fails inside the transaction. writeAgentJournalTurnRow returns nothing again, as on main.
…d options

A failed step no longer lets the steps after it write: each step checks, at its own turn in the
journal's queue, whether the write handed over just ahead of it completed, using the queue's count
of completed write bodies (a promise would report the failure only after the next step ran). The
sink fails only once every step has had its turn. The item step's `paced` size bypass and the
resolver's replacement `options` are removed; nothing planned uses them.
@brennanb2025 brennanb2025 changed the title Let structured-chat rows be found again after a restart, and admit one event's writes as one operation Admit one provider event's journal writes as one queued operation, decided when it runs Oct 5, 2026
The steps of one event now share one turn in the journal's write queue: a
loop writes each in its own transaction through the row writer's
synchronous writeRows (split out of enqueueRows) and stops at the first
throw. Prefix semantics and "nothing lands between the steps" now hold by
construction, so the completed-write counter on the queue, the step gate
and the allSettled barrier are gone; the queue is back to main's bytes.
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review summary

The problem this PR addresses. Structured native chat is getting a shared "timeline assembler" (#25064, stacked on this PR) so that new agents (Grok first, over the Agent Client Protocol) don't each need their own hand-written translator into Orca's chat history (the journal). That assembler needs one building block from the journal layer: a way to accept all the journal writes caused by one agent event as a single unit, with each write decided at the moment it actually runs, against the journal as it stands then.

User-facing change: none. Nothing calls the new code yet. The only code that runs differently today is Claude's turn-row writer, which moved to a shared module with identical behaviour.

What changed during review. The review found that an earlier version of this PR (and #25064) built a lot of machinery to recover from a situation that cannot happen in production: the assembler losing its memory while the agent process keeps streaming the same turn. On main, an agent process and its translator always live and die together, and the old turn is closed out before a new process's events are written. That machinery included a new persisted row field (providerItemRef), a provider-id-to-row index and a message-numbering scan. The persisted field was also the wrong design: it stored a Codex item id that Codex renumbers when a conversation is resumed, so after a restart the lookup could return the wrong row (reproduced). All of that is removed. What remains:

  • One event = one queued journal operation. It is accepted or refused as a whole. Its steps run back to back inside one queued write, each in its own database transaction, and execution stops at the first failed step (earlier steps stay written, later steps write nothing, the event sink fails). This is true by construction: an earlier fix inferred a failed step from a new counter on main's write queue; that counter is gone and main's write queue is byte-identical to main.
  • Settlement rows are written all-or-nothing through main's existing multi-row write (enqueueRows), with a guard that refuses a settlement naming one item twice before anything is written.
  • Two small text-batching hooks (dirty / markFlushed) for the assembler, and Claude's turn-row revision moved to a shared module, plus an extracted size/resolver function and an opt-in onlyWhileRunning rule the assembler uses (described accurately in the body; it is not a pure move).
  • The journal row writer and its collaborators are back to main's exact bytes, so the unreviewed conflict resolutions from the earlier refresh no longer exist.

Deferred (low impact, not blocking).

  • An event the sink already accepted before an earlier event's write failed still lands; this is main's existing sink rule for every agent lane. The session then fails and the restart cleanup settles what's left.
  • The duplicate-item guard refuses input rather than threading one revision counter across chunks (the only caller never produces duplicates).
  • The step writer doesn't report which steps wrote when it fails (nothing reads that).

Verified. Four review rounds plus a readiness checklist (no P0/P1/P2). Main's guarantee suites for the touched journal code pass on this branch (57 files / 647 tests in one run), plus the PR's own tests, including tests that fail with the stop-at-first-failure loop removed. CI on the final head ff089865ceb (current main merged in): typecheck and static analysis, all five unit-test shards, packaging (including Windows), cross-version wire compatibility and verify all pass.

Not verified. No live agent, no Windows/Linux run, no headless or SSH runtime; nothing is wired.

- journal-store.ts imports: main #24576 dropped journalStoreLoadedFields; this branch types
  appendResolvedItem off JournalItemAppender, so neither it nor JournalResolvedItem is imported.
- event-sink-queue: keeps this branch's journalItems; journalStopDecidesTurn takes main #24864's
  two arguments (openedBy plumbing removed on main).
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Merged current main into this branch (now e996bb1df42).

@brennanb2025

brennanb2025 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Earlier CI merges missed main's restored provider-handle import and the test-only parser dependency still needed by old release checkouts. Merged main 08a970a3f117; the branch's own changes are preserved, the submission-position test matches main with exactly one used import, and main's package/lock fix is inherited through the merge with no branch-authored dependency edits; current provider-handle test fixtures are retained. The prior broad run passed 4,473 tests; fresh-main checks passed 118 tests, with remaining local failures limited to stale stream-json/stream-chain dependencies, and scoped oxlint passed; new-head CI is pending.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 6, 2026 03:30
@coderabbitai

coderabbitai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 635c948c-d134-4900-bf8a-bbc3b4e642a5
📥 Commits

Reviewing files that changed from the base of the PR and between 08a970a and 383b0dc.

📒 Files selected for processing (14)
  • src/main/claude/claude-context-facts.ts
  • src/main/claude/claude-open-turn.ts
  • src/main/native-chat/agent-session-journal/journal-lifecycle-batch-appender.ts
  • src/main/native-chat/agent-session-journal/journal-row-writer.ts
  • src/main/native-chat/agent-session-journal/journal-step-writer.ts
  • src/main/native-chat/agent-session-journal/journal-store-collaborators.ts
  • src/main/native-chat/agent-session-journal/journal-store-contracts.ts
  • src/main/native-chat/agent-session-journal/journal-store.ts
  • src/main/native-chat/agent-session-timeline/agent-journal-turn-row-revision.ts
  • src/main/native-chat/agent-session-wire/agent-session-delta-coalescer.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-event-sink-queue.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-event-sink.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-transition.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-transition.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The changes add ordered structured transitions to the agent-session journal. They include resolved lifecycle batching, transactional row writes, and a step writer used by the journal store. The structured sink exposes transition operations, which resolve and append steps before publishing once when applicable. The changes also generalize turn-row revision APIs, add coalescer methods for dirty streams, and add tests for transition ordering, failures, settlement batches, and coalescer behavior.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 383b0

The transition API is not wired into an agent, and no actionable merge-blocking issue was established. The change is ready for normal merge checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 383b0

Existing behavior is preserved, and the new capability has no live caller. Risk is limited, but safe recovery from partially completed work still depends on future integrations.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated mutation scope remains the journal instance bound to the sink. The inspected new call path does not introduce cross-session database authority; failure can leave that journal with committed but unpublished transition steps.

Trust Boundaries and Controls

  • observed — Provider-derived item content still passes through journal-owned serialization, fence enforcement, and serialized-row validation before insertion. Extracting the synchronous write method preserves these controls from the base implementation.

Resilience and Maintainability Implications

  • observed — A step or publication failure marks the sink failed and prevents new admissions without undoing committed rows. Already handed-over operations may still land. Reopening replays durable rows, so future callers must reconcile their state with the persisted prefix rather than assume rollback.

Hardening Proposals

  • proposed — When a production producer adopts transitions, validate convergence after every durable prefix, interruption, and publication failure. Derive recovery decisions from journal state and verify that repeated execution preserves approval, tool, and turn terminal-state ownership.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 14 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: admitting one provider event’s journal writes as a single queued operation, with decisions made when the operation runs.
Description check ✅ Passed The description covers the change, rationale, testing, visual-proof exemption, compatibility considerations, and checklist. It identifies the linked work and explains that no separate issue is needed …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@brennanb2025
brennanb2025 merged commit c0b07d3 into main Oct 6, 2026
56 checks passed
brennanb2025 added a commit that referenced this pull request Oct 6, 2026
Main squash-merged D1 #24990 (from 320f347) and C1a #25141 (383b0dc). Conflicts:
- #25720 dropped the launch-command override gate from native-chat create support and renamed the
  route input to startsOutsideWorkspaceRoot: main's version, with D3's agent-generic typing and
  host structured-agents input.
- the model catalog store's refresh: D3's agent: string plus main's new lister parameter.
- #25654's tool-run header restyle lands in C5's NativeChatToolRunCallCounts, which holds that span.
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