Repository navigation
feat(ai): Ask this session (core + Pi) - #1668
Merged
Merged
Conversation
Ask AI can be answered by the agent session that opened Plannotator. Adds the host-neutral SessionBridge interface and the session-bridge provider behind the existing /api/ai/* endpoints (both runtimes), the UI default/busy/fallback flow, and the Pi bridge for review, annotate and last. Also cancels the SSE stream on client disconnect in the Pi server, matching the Bun server.
…r-started question agent_end fires once per agent run, and Pi retries a retryable error (overloaded, rate limited) or continues after an overflow compaction inside the same prompt. The bridge reported the first failed attempt as the answer and stopped listening while Pi went on to answer. An error end now waits for agent_settled (Pi >= 0.80.4), or for the session to go idle on older Pi, and a retry that starts answering clears it. The start watchdog checked once at 15s and gave up silently when the session was busy, so a question steered into a turn that Pi then dropped (user aborted it) waited forever. It now re-checks until the session is idle.
… guard)
A bridge question is a real turn, with tools, in the user's own agent
session. Nothing checked the Host header on /api/ai/*, so a DNS-rebinding
page (evil.example resolved to 127.0.0.1) could create a session-bridge
session or query one. Creating a session on, or querying, the
session-bridge provider now requires the runtime's
authorizeSessionBridgeRequest guard to pass: both runtimes check that the
Host header is localhost, a 127.x literal or [::1] with the server's own
bound port, and refuse with 403 { code: session_bridge_forbidden_host }.
Without a guard the bridge never answers. Other providers never consult
it, so non-bridge Ask AI is unchanged.
The predicate lives in packages/shared/loopback-host.ts (vendored to Pi),
which now owns isLoopbackHostname; live-proxy-core re-exports it. The VS
Code cookie proxy forwards Host as the session URL's host (localhost:PORT),
so it passes.
session-bridge.ts drops TypeScript parameter properties: endpoints.ts now
imports it, and Pi's AI runtime must still load under Node's strip-only
TypeScript (ai-runtime-disconnect.test.ts runs it in a real Node).
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1 of "Ask this session" (build order steps 1-3 of
.product/drafts/session-ask-ai/DESIGN.md): Ask AI answered by the agent session that opened Plannotator.Core (
packages/ai/session-bridge.ts, vendored to Pi)SessionBridgehost interface (ready | busy | blocked | gone,turn/transientmodes,ask, optionalinterrupt) and asession-bridgeprovider behind the existing/api/ai/*endpoints in both runtimes. It is registered last, so the server default does not change.agent_busy. The client then re-asks withbusyPolicy: "wait"or"interrupt"on/api/ai/query.UI
Pi
pi-session-bridge.tscovers review, annotate and last. Each question is a real turn (sendMessagewithcustomType: "plannotator-ask"andtriggerTurn), streamed from the session's events.Where Pi differed from the design
pi.onreturnsvoidin the installed Pi 0.84/0.85; only 1.0 returns an unsubscribe. So the listeners are registered once at load and route events to the active question.pi.sendMessagereturnsvoidand reports async failures to Pi's own error channel. A watchdog fails a question that never reaches the session.ctx.abort()and then asks. Pi's steer would also work, but it merges the question into the user's turn.Verified live in Pi 0.85.1 (RPC mode, real model) for annotate, last and review:
agent_busy, then wait, then the answer;new_sessiongivessession_gone.A headless Chromium run of the annotate UI showed the label, no model picker, the busy choice, the waiting status and the answer.
Tests: typecheck,
bun test, the CI DOM lists,build:piand the guides.show manifest check all pass.Not in this PR: Pi plan review.
submit_planawaitsopenPlanReviewBrowserinside a sequential tool, so the session is blocked until the decision. To make it non-blocking:startPlanReviewServer(the Bun option already exists).