Skip to content

fix(agent-gateway): seed agent phase when a transcript attaches mid-turn - #365

Merged
elkaix merged 1 commit into
mainfrom
fix/transcript-seed-phase-on-attach
Oct 2, 2026
Merged

elkaix merged 1 commit into
mainfrom
fix/transcript-seed-phase-on-attach

Conversation

@elkaix

@elkaix elkaix commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Requirement or Bug

Resolve #350

Bug Reproduction Steps

In transcriptContract.e2e.test.ts S3, add await new Promise((r) => setTimeout(r, 3000)); after submitPrompt. It then fails every time with expect(mid.meta.agent).toBeDefined(). Without the sleep it fails about 1 run in 4, and more often under load.

Root Cause

The transcript store binds to the event bus lazily, on the first transcript request. meta.agent.phase comes only from the projector's phase merge, and that merge runs only when a new bus event arrives. On a late attach, subscribeAgent (coreBinding.ts) restores the running turn with seedActiveTurn, but it does not restore the phase. seedPendingInteractions then adds the approval. The turn is blocked on that approval, so no further event comes and meta.agent stays undefined. In the product, a client that opens or reloads a session while an approval is pending shows the approval with no agent status. Fundamental fix.

Code Changes

  • coreEventMap.ts: new AgentTranscriptProjector.seedPhase(). It recomputes the phase from the activity snapshot and the pending approvals, and returns one meta.merge. The tracker set-up moves to tracker(), which phaseFor reuses.
  • coreBinding.ts: when attaching to a turn that is already running, apply seedPhase() after seedActiveTurn. Idle and new agents are not touched. A later phase event with the same value is deduplicated by the tracker's lastPhaseKey.
  • Test: transcript.test.ts checks that seedPhase() gives awaiting_approval for a turn blocked on an approval.

Not in scope: meta.agent.model and meta.agent.permission on late attach. S3 needs only the phase.

Behavior Changes and Affected Users

Behavior Before After Who relies on the old behavior Escape hatch
Transcript first opened while a turn is running meta.agent missing until the next phase event (never, if the turn is blocked on an approval) meta.agent.phase is set immediately None. Clients already handle meta.agent.phase from live events None needed

Consumers: web, desktop, and inspector clients that read meta.agent.phase. The wire shape is unchanged. Verification: forced-late S3 fails 2/2 without the fix and passes 2/2 with it. Full agent-gateway suite: 1408/1408.

No quarantine for S3 exists in the repo, so there is nothing to remove.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (external PRs: issue must have a maintainer's /approve).
  • I have added tests that prove my feature works.
  • The behavior-change table above is complete, and every removed behavior or flipped default is named in the changeset and either has an escape hatch or was explicitly approved by a maintainer in this PR.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

A transcript bound to a turn already blocked on an approval got the
pending interaction but no meta.agent, and no later event repaired it.
@coderabbitai

coderabbitai Bot commented Oct 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 32 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: PyModel/pythinker-code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fa285a9a-961f-4c4b-9791-cc7ec680aa3b
📥 Commits

Reviewing files that changed from the base of the PR and between ecc2c3b and 811e575.

📒 Files selected for processing (4)
  • .changeset/transcript-phase-on-attach.md
  • packages/agent-gateway/src/services/transcript/coreBinding.ts
  • packages/agent-gateway/src/services/transcript/coreEventMap.ts
  • packages/agent-gateway/test/services/transcript.test.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@pymodel/pythinker-code@811e575
npx https://pkg.pr.new/@pymodel/pythinker-code@811e575

commit: 811e575

@elkaix
elkaix merged commit 81f1070 into main Oct 2, 2026
26 checks passed
@elkaix
elkaix deleted the fix/transcript-seed-phase-on-attach branch October 2, 2026 23:33
elkaix pushed a commit that referenced this pull request Oct 3, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @pymodel/pythinker-code@2.5.2

### Patch Changes

- [#364](#364)
[`c431d50`](c431d50)
Thanks [@elkaix](https://github.com/elkaix)! - A session whose model was
deleted or lost its provider switches to the best available model at the
next turn, with a warning, instead of failing the turn.

- [#365](#365)
[`81f1070`](81f1070)
Thanks [@elkaix](https://github.com/elkaix)! - Clients that open a
session while a tool approval is pending now show the agent's status
instead of none.
## @pymodel/pythinker-desktop@1.6.2

### Patch Changes

- [#364](#364)
[`c431d50`](c431d50)
Thanks [@elkaix](https://github.com/elkaix)! - A session whose model was
deleted or lost its provider switches to the best available model at the
next turn, with a warning, instead of failing the turn.

- [#365](#365)
[`81f1070`](81f1070)
Thanks [@elkaix](https://github.com/elkaix)! - Clients that open a
session while a tool approval is pending now show the agent's status
instead of none.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

Transcript meta.agent sometimes never arrives while an approval is pending (S3 e2e flake)

1 participant