Repository navigation
feat(acp): a sign-in prompt on an ACP agent's error output ends the start or turn signed out - #28467
Conversation
|
Some chat agents print a browser sign-in link on their error output and then wait, leaving chat startup or a turn hanging. This PR adds an optional detector that uses Orca's usual agent shutdown path and reports signed out; no agent enables it yet, so current chat behavior is unchanged. Review fixed a privacy defect: a fragmented sign-in line longer than the buffer could lose its prefix and expose the link in retained output. Commit Two review rounds, an architecture challenge, and dedicated readiness/performance review found no remaining new issue. All 712 targeted Node tests and ordinary typecheck passed. All 13 applicable final CI jobs passed, including five Node test shards, relay integration, Linux/Windows packaging, repository guards, line budget, and static analysis/typecheck. Local Bun 1.3.14 could not run the pinned CI typecheck command, which passed in CI. Accepted edge: if the process exits before buffered sign-in output is read, startup reports the agent exit while withholding the link. Deferred to the follow-up that enables Antigravity in Chat UI (stack PR 8): verify how a mid-turn signed-out failure and the subsequent session exit appear together. Electron QA is N/A here because the detector has no enabled agent; live app flows and parser throughput were not measured. The PR remains open. |
ac1c23b to
036c13a
Compare
4dea606 to
eeecb2d
Compare
43ecec5 to
b2c75e1
Compare
eeecb2d to
e73668c
Compare
9503d1b to
e50c315
Compare
e73668c to
a94f0d1
Compare
ddc824a to
edcb3ec
Compare
a94f0d1 to
a6cc794
Compare
edcb3ec to
b12a4d9
Compare
a6cc794 to
6b74006
Compare
b12a4d9 to
5c2cc7b
Compare
6b74006 to
6873ffe
Compare
5c2cc7b to
59b548c
Compare
6873ffe to
80b124d
Compare
59b548c to
540bd9d
Compare
80b124d to
4c5c7ce
Compare
540bd9d to
f7c8053
Compare
4c5c7ce to
6b4c263
Compare
f7c8053 to
724f8fd
Compare
6b4c263 to
f090b03
Compare
b485ce0 to
36a9859
Compare
26dfd2c to
aaa2b56
Compare
36a9859 to
47613e5
Compare
aaa2b56 to
a3b2598
Compare
47613e5 to
b4ca6d9
Compare
a3b2598 to
49376f6
Compare
b4ca6d9 to
3495a4e
Compare
49376f6 to
42990a2
Compare
1ab34a3 to
6aecbf4
Compare
da7a206 to
bea2a26
Compare
7775094 to
e2abbf0
Compare
faefb84 to
fff5133
Compare
4f767db to
fdbb87d
Compare
586a3f2 to
30ac0e1
Compare
…r turn signed out An agent that waits for a browser sign-in prints a link on stderr and blocks for minutes. A launch spec can now name that line (signInPrompt); the connection then closes with a typed sign-in failure through the existing process owner, so a start reads notSignedIn and a running turn fails signed out instead of settling unknown. The matched line, which carries the sign-in URL, never enters the retained stderr tail, errors or diagnostics.
fdbb87d to
796e987
Compare
📝 Walkthrough
Priority: ⬇️ Low Merge Risk: 🔵 Low · up to
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
83b9a698-6575-4aaa-ba17-078de1caf612
📒 Files selected for processing: 9
src/main/acp/acp-agent-connection.test.tssrc/main/acp/acp-agent-connection.tssrc/main/acp/acp-launch-specs.tssrc/main/acp/acp-structured-acquire.tssrc/main/acp/acp-structured-session-adapter.tssrc/main/acp/acp-structured-session.tssrc/main/acp/acp-structured-sign-in.test.tssrc/main/acp/acp-structured-turns.tssrc/main/provider-process/managed-provider-process.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.
…t is dropped, so its URL never reaches the kept tail
There was a problem hiding this comment.
🧹 Nitpick comments: 1
src/main/acp/acp-structured-sign-in.test.ts: 1
81-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPreserve preacceptance coverage and add accepted-turn close coverage.
The existing
AcpAuthRequiredErrortest does not accept the turn, so it uniquely covers dispatch refusal. The suite covers accepted and unaccepted turns foragent.fail, but not forAcpSessionRuntime.prototype.close. Add a separate accepted-turn scenario for the connection-close failure timeline.Suggested fix
it('ends a running turn signed out when the connection closes for sign-in', async () => { const rig = await openAcpAdapterRig({ script: (agent) => agent.on('session/prompt', () => {}) }) await rig.acquire() await sendHello(rig, 'first') await rig.frame('session/prompt') // The protocol close the real connection makes at a sign-in prompt line on stderr. AcpSessionRuntime.prototype.close.call(rig.child(), new AcpAuthRequiredError('Sign in')) await rig.settle() expect(rig.settled).toContainEqual( expect.objectContaining({ clientMessageId: 'first', state: 'rejected', rejection: expect.objectContaining({ kind: 'notSignedIn' }) }) ) }) +it('fails an accepted turn as signed out when the connection closes for sign-in', async () => { + const rig = await openAcpAdapterRig({ + script: (agent) => + agent.on('session/prompt', (frame) => { + agent.notify('session/update', { + sessionId: PROVIDER_SESSION, + _meta: promptMeta.parse(frame.params)._meta, + update: { + sessionUpdate: 'agent_message_chunk', + content: { type: 'text', text: 'started' } + } + }) + }) + }) + await rig.acquire() + await sendHello(rig, 'first') + await rig.frame('session/prompt') + AcpSessionRuntime.prototype.close.call(rig.child(), new AcpAuthRequiredError('Sign in')) + await rig.settle() + const failures = (await rig.rig.rows()).flatMap(({ body }) => + body.kind === 'status' && body.failure ? [body] : [] + ) + expect(failures).toHaveLength(1) + expect(failures[0]?.failure).toMatchObject({ kind: 'notSignedIn' }) +})
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
17edb4d7-142d-417b-831f-ab17187f662c
📒 Files selected for processing: 2
src/main/acp/acp-agent-connection.test.tssrc/main/provider-process/managed-provider-process.ts
🚧 Files skipped from review as they are similar to previous changes: 2
- src/main/provider-process/managed-provider-process.ts
- src/main/acp/acp-agent-connection.test.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
Antigravity chats need Google's separate Antigravity chat server. An earlier version of this stack downloaded it silently the first time a chat started: about 18 seconds of "Working for Ns" with no progress and no Cancel, and every extra chat opened started another download. Now nothing downloads until the person clicks Install, which shows the size, progress and Cancel in Settings and in the new chat.
This PR handles what that server does once installed but signed out. It doesn't answer "please sign in". It prints a sign-in link on its error output and then waits up to five minutes for someone to open it. Nobody sees that link in a chat, so the chat just hangs. With this PR an agent can declare "this line means I'm waiting for a browser sign-in". When Orca sees that line, the chat stops waiting right away and shows Orca's normal "not signed in" state.
What Changed
This revision: no code change. The differences list below was corrected: the per-agent matcher on the launch description is how the common pattern does it too, so it is no longer listed as a difference, and the long-line case is now listed.
signInPrompt(line). Orca reads that agent's error output line by line. On a match it closes the connection with its existing typed sign-in error,AcpAuthRequiredError. A chat start fails as not signed in, and a running turn fails the same way it does when the agent itself answers "sign in required". The matched line holds the sign-in link, so it never goes into the retained error tail, error messages or diagnostics.Mechanism:
spawnManagedProviderProcesstakes an optionalonStderrLine(line): booleanon the existing error-output drain. With it, output is split into complete lines and a line the callback claims is withheld from the tail. The pending partial line is capped at the tail size (8 KiB), so a long link split across chunks is still classified by its start. Without the callback, behaviour is unchanged.AcpStructuredTurns.end(reason, cause)). When the cause is the sign-in error, the running turn takes the same failure path as a sign-in refusal from the agent (now one shared method) instead of settling "unknown". The helper for a send refused before it was written moved beside it asrejectedAcpDispatch, with no behaviour change.Why
The common pattern for agents that sign in through a browser is to detect the waiting state and show a clear signed-out state, not to hang, and it does so the same way: a per-agent error-output handler handed to the generic agent runtime. Detecting the line through data on the launch spec keeps agent names out of shared code. Ending the turn through the existing sign-in failure path reuses what the chat already shows for "not signed in" rather than adding a new state.
Linked Issue
N/A (maintainer; part of the Antigravity Chat UI stack).
Visual Proof
This PR changes nothing visible on its own; the agent that sets the field arrives in a later PR. The result it produces was captured in a real run of the whole stack (M4Air, build
d871611d303, a throwaway profile, nobody signed in, driven over the Chrome DevTools Protocol only): a message sent to a new Antigravity chat ended as "Your message was not sent. Sign in to Antigravity." instead of the chat waiting, and the sign-in link did not appear in the error text.This screenshot was taken before this PR's last review fix (long lines no longer keep their start in the saved error output). That fix is covered by a unit test, not by a screenshot.
Testing
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Connection test over the existing fixture process: a pending prompt, a noise line, then the sign-in line split across two chunks, with a link longer than the 8 KiB partial-line cap. The prompt rejects with the sign-in error, the process exits, the link appears in none of the error, diagnostics or retained tail, and the noise line is kept.
Session test: a running turn whose connection closes with the sign-in error settles as not signed in. It fails without the turn-tracker change.
pnpm tc:nodeand all ACP and provider-process tests (712) passed. The change is platform-independent.Review
Agent skill upstream boundary
Notes
Differences from the common pattern
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)