Skip to content

cli ask: print console URL and render the agent's response - #17

Merged
boristane merged 3 commits into
mainfrom
claude/ask-console-url-and-response
Aug 10, 2026
Merged

cli ask: print console URL and render the agent's response#17
boristane merged 3 commits into
mainfrom
claude/ask-console-url-and-response

Conversation

@claude

@claude claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

Requested by boris · Slack thread

Before

polylane thread ask "…" printed a bare thread id and exited. The answer never appeared: the durable-thread server acks the CLI's WebSocket chat request with an immediate empty done sentinel, so the old wait resolved instantly with empty text. polylane thread continue had the same bug via the same WebSocket path.

$ polylane thread ask "why did last night's deploy fail?"
Thread: thrd_38mg3o4ibc92h8t2efn8csrh

$

After

The command prints the console URL for the thread and then actually shows the agent's answer in the terminal:

$ polylane thread ask "why did last night's deploy fail?"
Thread: https://console.polylane.com/acme/threads/thrd_38mg3o4ibc92h8t2efn8csrh

⠹ Waiting for the reply…        (spinner, stderr only)

The deploy failed because the api-gateway worker exceeded its startup CPU
limit after the new dependency bundle pushed cold-start work over the cap. …
$
  • thread continue now behaves the same way: console URL on stderr, the new turn's reply on stdout (prior messages in the thread are excluded from the rendered reply).
  • Status lines and the spinner go to stderr; stdout carries only the reply text.
  • In text mode (TTY) the reply streams incrementally by default — no flag needed; the spinner shows until the first token arrives. --stream is kept as a deprecated no-op.
  • --output json (and piped stdout, which auto-selects json) waits for the complete reply and emits { thread: { id, name, url }, status, text, messages } — nothing is lost.
  • If the agent is still working after the 10-minute wait ceiling, the CLI says the reply is still being generated and prints the console URL (json: "status": "pending" with any partial text).
  • --no-wait output now includes the URL alongside the id.

How

Thread creation and message dispatch are async server-side, so the CLI now sends the prompt via POST /v1/messages (202 accepted) and polls GET /v1/threads/{ws}/{id} until the thread is idle (runningSince and awaitingAgentsSince both null — the same signal the console's threads table uses for "Completed") with an assistant reply, then fetches GET /v1/messages/{ws}/{id} and renders the text parts. The console URL comes from the thread's _html_url (already returned by the API), with a workspacesGet slug-based fallback. Poll interval 2s, timeout 10 minutes; a brief idle flicker between agent iterations is tolerated by requiring several consecutive idle polls before accepting a reply without text. The helper lives in src/client/thread-poll.ts with tests in test/thread-poll.test.ts.

thread continue — originally noted here as a same-bug follow-up — is now fixed in this PR too: it rides the same poll helper with a new ignoreIds option (messages that existed before the send are excluded, and the poller reads the newest page so long threads see fresh replies). With continue migrated, the old WebSocket path (src/client/thread-chat.ts) had no callers left, so it and the ws dependency are removed. The shared console-URL helper moved to src/commands/thread/console-url.ts.

🤖 Generated with Claude Code

https://claude.ai/code/session_017dH9CyqJdQDNAnyS5Tg2L8


Generated by Claude Code

The durable-thread server acks the websocket chat request with an
immediate empty done sentinel, so the old WS wait resolved instantly
with no text: the command printed a bare thread id and exited without
ever showing the agent's answer.

thread ask now sends the prompt via POST /messages (async, 202) and
polls the thread until it is idle (runningSince/awaitingAgentsSince
null) with an assistant reply, then renders the reply text. The bare
thread id is replaced by the thread's console URL (_html_url, with a
slug-based fallback). --stream prints the reply incrementally from the
in-progress persisted message; the poll gives up after 10 minutes and
points at the console URL instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dH9CyqJdQDNAnyS5Tg2L8
@polylane

polylane Bot commented Aug 10, 2026

Copy link
Copy Markdown

Warning

Polylane could not verify the production impact of this pull request.

Checked the CLI polling changes against nominal-api-threads-prod (254 req/h, 0 errors); this is a client-side npm tool, not a deployed resource, and the polling hits existing endpoints the console already uses at trivial volume.

View the full analysis →

Dependency changes

Package Change Jump Release age
@types/ws removed (was 8.18.1)
ws removed (was 8.21.1)

view-investigation review-in-polylane disable-pr-reviews

Polylane could not find the cloud resources this repository manages, so this review looked at the entire cloud account. Connect this repository to its resources and the next review will focus on exactly what this code deploys to.

connect-resources

Polylane analysed 7ffc084 for production impact.

claude added 2 commits August 10, 2026 04:18
Rewire thread continue onto the same async-send + poll path as thread
ask: post via messages.post, print the console thread URL on stderr,
and poll with waitForAssistantReply until the agent's reply lands.
Pre-existing messages are excluded via a new ignoreIds option so only
the new turn's reply is rendered; the poller now reads the newest page
of messages so long threads see fresh replies.

The old durable-thread WebSocket path resolved on the request ack
(an empty done sentinel), so continue printed nothing. With continue
migrated, thread-chat.ts had no callers left — removed along with the
ws dependency. threadConsoleUrl moved to a shared module used by both
ask and continue.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dH9CyqJdQDNAnyS5Tg2L8
thread ask and thread continue now print the reply incrementally in
text mode without needing --stream. Piped stdout still auto-selects
json, and --output json still waits for the complete reply. The
--stream flag is kept as a deprecated no-op so existing invocations
keep working. The spinner shows until the first token arrives.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dH9CyqJdQDNAnyS5Tg2L8
@boristane
boristane merged commit b088a05 into main Aug 10, 2026
4 checks passed
boristane added a commit that referenced this pull request Aug 10, 2026
PR #23 added ws and @types/ws alongside workspace-socket.ts, but the
PR #17 merge carried an older package.json that removed them again,
breaking typecheck on main (TS2307: Cannot find module 'ws'). Restore
both entries from the pre-#17 state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.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.

2 participants