Skip to content

AI handoff: second handoff's auto-send doesn't fire into an existing (hydrating) build conversation #2450

Description

@os-zhuang

Residual from #2449 (ADR-0057 P4 follow-ups). Not a regression — before #2449 a second handoff did nothing at all; now the context re-carries but the new prompt still needs one manual send.

Symptom (observed live, local rig)

  1. Ask agent declines request A → "Open in Builder →" → build conversation minted, prompt A auto-sends, blueprint proposed (Awaiting Approval). ✅ (fixed by fix(console-ai): reliable handoff auto-send + second-handoff context re-carry (ADR-0057 P4) #2449)
  2. Back on the ask thread, decline for a different request B → click the second "Open in Builder →".
  3. The route lands on the existing build conversation (singleton per user/app/product), ?handoffPrompt=B&parentConversationId=… present — but no POST …/chat fires. The composer stays empty; the surface still shows blueprint A awaiting approval.
  4. A manual send in the build composer works and does carry the re-armed context.parentConversationId (verified on the wire) — so the fix(console-ai): reliable handoff auto-send + second-handoff context re-carry (ADR-0057 P4) #2449 re-carry is functioning; only the auto-send is lost.

Suspected mechanism

For an existing conversation, conversationId is already present at ChatPane mount, so useDeferredFirstSend's replay fires immediately — likely before useObjectChat/useChat finishes hydrating initialMessages (and/or while the pane is mid-remount on the ask→build route switch). The send is issued into a hook instance that's about to be torn down or not yet ready, and is dropped. The fresh-conversation path has a natural "pending id" phase that orders things correctly, which is why #2449's fix works there.

Files: packages/app-shell/src/console/ai/AiChatPage.tsx (useDeferredFirstSend, the ADR-0057 P4 handoff seed effect, pendingFirstMessageSeq), packages/plugin-chatbot/src/useObjectChat.ts.

Suggested direction

Gate the deferred replay on hydration-ready for the resume case — e.g. replay only once the pane's useObjectChat reports messages hydrated (or defer via a requestAnimationFrame/effect tick after initialMessages are applied). Add a live-rig proof: second handoff → POST …/chat fires automatically with context.parentConversationId and prompt B.

Product question (separate but adjacent)

When the second handoff lands on a conversation whose blueprint is still Awaiting Approval, what should happen to the pending blueprint? Today it just sits there; the new request arrives with no UI acknowledgment of the pending plan. Worth a small UX decision (banner "你有一个待确认的方案" / queue / supersede).

Refs: #2449, #2444, #2439, cloud#819/#820, ADR-0057 §P4.

Activity

  1. added a commit that references this issue on Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions