feat(overlay): project agent stages onto overlay messages (Issue #8790) - #8797
Conversation
The overlay protocol dropped `custom_content` when it replaced the chat's internal message entity with a narrow projection, which took the agent's execution stages with it. A host that reacted to tool calls — refreshing its own view once a particular tool had run — lost its only signal and was left with GPT_END_GENERATING plus an unconditional refresh. `OverlayChatMessage` now carries an optional `stages` array. The protocol keeps its own `OverlayMessageStage`/`OverlayStageStatus` types rather than re- exporting `Stage` from chat-shared, and `toOverlayMessages` translates between them explicitly, so an unrecognised status degrades to "still running" instead of crossing the boundary untranslated. Stage attachments are not projected: they carry host-resolvable URLs the protocol has no counterpart for. Stages stay a read, not a push — a host subscribes to GPT_END_GENERATING and calls getMessages(). A per-stage streaming event is the follow-up slice in Issue #8790. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
✅ security-review: No security issues found. Stage data flows through postMessage JSON serialization only; no new innerHTML, eval, or injection surfaces introduced. |
|
|
||
| `stages` is the one part of `custom_content` the protocol projects: a message | ||
| that carries agent execution stages exposes them as `OverlayMessageStage[]`, | ||
| with `index`, `name`, `status` (`null` while running, otherwise |
There was a problem hiding this comment.
code-review · fyi
FYI: the migration-guide wording that stage projection syncs with the chat's own stages. In the chat, stage content/name are delta-merged across chunks and a first-chunk name: null coalesces to '' (apply-chunk.ts). A host that pattern-matches on stage name or content should expect display-merged text, not exact per-chunk labels. The doc's phrase 'the one part of custom_content the protocol projects' is fine.
| */ | ||
| const toOverlayStageStatus = ( | ||
| status: Stage['status'], | ||
| ): OverlayStageStatus | null => { |
There was a problem hiding this comment.
code-review · fyi
FYI (not a defect): toOverlayStageStatus maps any unrecognized StageStatus value to null ('still running'), as the comment documents. This silently conflates 'legitimately running' with 'unrecognized settled value'. Harmless today since StageStatus has only Completed/Failed, but worth remembering if a third state (e.g. cancelled/interrupted) is added upstream — the overlay callers would see it as in-progress.
| }); | ||
| }); | ||
|
|
||
| it('getMessages exposes the agent stages attached to a message', () => { |
There was a problem hiding this comment.
code-review · optional
Optional: good round-trip coverage through the bridge. One behavioral surface without a direct test: the sendMessage response messages (the README example reads stages off sendMessage/getMessages results). Both routes call toOverlayMessages on the same ref, so coverage is effectively shared, but an explicit assertion that the post-send messages include stages when the ref already contains them would lock the send-path contract too.
4 finding(s) posted as inline review comments. |
The overlay protocol dropped
custom_contentwhen it replaced the chat's internal message entity with a narrow projection, which took the agent's execution stages with it. A host that reacted to tool calls — refreshing its own view once a particular tool had run — lost its only signal and was left with GPT_END_GENERATING plus an unconditional refresh.OverlayChatMessagenow carries an optionalstagesarray. The protocol keeps its ownOverlayMessageStage/OverlayStageStatustypes rather than re- exportingStagefrom chat-shared, andtoOverlayMessagestranslates between them explicitly, so an unrecognised status degrades to "still running" instead of crossing the boundary untranslated. Stage attachments are not projected: they carry host-resolvable URLs the protocol has no counterpart for.Stages stay a read, not a push — a host subscribes to GPT_END_GENERATING and calls getMessages(). A per-stage streaming event is the follow-up slice in Issue #8790.
Description of changes
Applicable issues
UI changes
<Please, provide Screenshots or Figma links>
Checklist
(Issue #<ISSUE_ID>)(comma-separated list of issues)PR title cheatsheet
<type>[optional scope]: <description>feat- A new featurefix- A bug fixdocs- Documentation only changestest- Adding missing tests or correcting existing testsci- Changes to our CI configuration files and scriptschore- Other changes that are minor and/or not user-facingchatoverlaysharedsandbox-overlayvisualizer-connector