Conversation
Co-authored-by: Roomote <roomote@roocode.com>
Co-authored-by: Roomote <roomote@roocode.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
…fter completion (#5) Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…hooks (#3) * [Fix] Treat a clarification question as a valid end of turn in Slack hooks Asking the user a question was not an accepted terminal state: after a send_chat_reply with purpose "clarification", the stop hook blocked with current_turn_nonterminal_reply, the harness injected up to three closeout reminders, and the model dutifully posted redundant "Paused here — I'm waiting on your answer" echo messages right after the question. A clarification is a visible handoff exactly like a closeout — the turn ends waiting on the user's answer — so the anti-silence hooks now treat it as terminal, with the same staleness rule: non-Slack work after the question invalidates it and a fresh reply is required before stopping. - recordChatReplySatisfaction stamps terminal state for clarification replies, so staleness tracking applies to questions too. - The stop hook accepts clarification in its terminal-satisfaction checks (including legacy states written by pre-deploy workers); ack and progress still block. - The silence hook's terminal check mirrors the same policy so post-question work is stamped consistently. - OpenCode todo bookkeeping (todowrite/todoread) no longer stales a terminal reply: the exemption list only knew the legacy update_plan name, so a post-closeout todo update forced a redundant "closed this turn" follow-up message. - The send_chat_reply tool description now says a clarification ends the turn when the next step depends on the user's answer, and not to follow it with a separate "waiting on your answer" message. Verified end-to-end against the mock Slack harness with a live planner task: the question turn now ends cleanly (terminal state stamped, no echo for 3+ minutes where it previously arrived within one), and the answer round-trip completes with a single closeout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Update pinned send_chat_reply descriptions in tool-descriptions test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
#8) Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…arity (#9) Co-authored-by: Roomote <roomote@roocode.com>
…loy prompt (#10) Co-authored-by: Roomote <roomote@roocode.com>
…odels (#11) Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* Improve Microsoft Teams setup flow (#550) * Add Teams setup redirect guidance * Fix onboarding frame scrolling * Make Teams reconnect message more human * Send Teams chat images as attachments * Require Teams bot fields during setup * ui * setup ui * feat(setup): offer downloadable Teams app package in the setup flow * feat(setup): simplify Teams bot credential entry * feat(setup): require shared Teams app credentials * refactor(setup): split provider setup experiences * chore(web): remove stale comms provider import * chore(setup): keep provider setup props local * feat(setup): clarify Microsoft Teams setup steps * copy * feat(setup): refine Teams app setup flow * test(web): mock tooltip in comms settings tests --------- Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com> * [Fix] Preserve Teams image attachments when clearing thread reply footers Keep original Bot Framework attachments when a later footer-bearing Teams reply rewrites the previous message, and remove a stray partial Tailwind class from provider setup URL styling. --------- Co-authored-by: Bruno Bergher <bruno@roocode.com> Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…ank (#17) Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…rompts (#16) Co-authored-by: Roomote <roomote@roocode.com>
…ttles (#21) The first callbacks a docker worker makes (cloudJobs.dequeue / resume) go through the public URL, and a freshly (re)started ngrok/Caddy edge can briefly answer 5xx or without a JSON content-type. The worker failed the whole job on the first bad response, orphaning it in 'dequeued'. Claiming a job is idempotent server-side (FOR UPDATE SKIP LOCKED), so add the claim mutations to the retryable-path allowlist with a longer budget (6 attempts, ~31s of backoff). Also have the dev CLI poll the API health route through the public edge after starting services, so local stacks don't hand jobs to workers before the edge is serving. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…egram task entry (#22) Testing harness (packages/communication): - MockTelegramServer: fake Bot API (sendMessage, sendPhoto, editMessageText, reactions, buttons, webhooks) with /mock/state + /mock/events control plane and signed update dispatch into the real webhook handler. Enforces real Telegram limits (4096 chars, unknown chats, missing reply targets) and auto-computes entities so bot-command/mention detection matches production. - TELEGRAM_API_BASE_URL env override reroutes every runtime provider construction to the harness (mirrors SLACK_API_BASE_URL). - CLI runner (mock:telegram), LLM-judged eval runner (eval:telegram-scenario) with three scenario fixtures, and the mock-telegram-testing skill with a user-journey scenario catalog. Routing confirmation (apps/api telegram handler): - When the router is below 0.95 confidence, remapped, or picks all-repos while environments exist, task entry posts a compact Yes/Nope card that auto-starts the suggestion after ~5s; Nope edits the same message into a workspace picker (no timer). Router fallback shows the picker directly instead of silently launching in all repos. - Pending choice lives in Redis (one-shot GETDEL claim; 64-byte-safe callback data; requester-only clicks; Nope re-keys state so the timer can never fire a rejected suggestion; superseding requests invalidate stale cards). Suggestion-button launches skip the card. - New TelegramCommunicationProvider.editMessageText with HTML-to-plain fallback, used to finalize cards in place. Verified with 56 API handler tests + 17 harness tests and a live end-to-end run through the mock harness against the dev stack (card, Nope-to-picker, Nevermind, timer no-op, zero jobs created). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
* feat: provision environments declaratively from files at startup * fix: contain declarative dir failures and defer orphaning on invalid definitions --------- Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
Co-authored-by: Roomote <roomote@roomote.dev>
…ilently (#32) Messages typed on the task page while a turn is in flight were only appended to the runtime prompt queue and never delivered until the turn ended - unlike Slack/Teams/Telegram follow-ups, which steer. With a request_user_input question pending this deadlocked the task entirely: the turn never ends, so the queued message never drains. The web sendPrompt path now passes autoSteerWhenQueued: true end to end (web command -> sandbox-server procedure -> harness manager), so running sends use OpenCode native mid-turn injection, falling back to queued-prompt cancel/replay when injection fails or a question is pending. The optimistic UI places the message in the transcript rather than the queued-messages surface to match. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… flips (#33) The request_user_input panel (and the free-text answer path in the prompt input) were gated on taskPhase === 'waiting_for_user_input'. A queued or steered follow-up can flip the reported phase back to running while the harness turn is still blocked inside the question tool - in that state the question vanished from the UI and could never be answered, deadlocking the task. Visibility now tracks the live pendingUserInputRequests themselves, which the runtime clears on answer, cancel, and turn teardown. The free-text answer routing keys off the active pending request for the same reason. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…r JSON (#34) When an OpenCode session errored (e.g. the provider rejected the model with a 403), the transcript showed the entire JSON.stringify of the error - status codes, response headers, provider metadata - as an assistant message. Extract the human-readable provider message for the transcript and keep the full payload in the harness log for debugging. Seen on staging when the default Grok 4.5 model 403'd via OpenRouter: the chat rendered a wall of cf-ray headers and stripe CSP noise instead of "The model grok-4.5 is not available in your region." Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…lable (#36) * [Fix] Show initials instead of full name when avatar image is unavailable * [Fix] Update profile avatar test for initials accessibility model * [Fix] Fall back to initials for already-broken cached avatars --------- Co-authored-by: Roomote <roomote@roomote.dev>
…ry refetch (#37) The live task page reconstructed history through two different code paths: initial load used the envelope loader (loadAcpEnvelopes, the same builder the always-correct historical view uses), but every subsequent refetch patched the in-memory list envelope-by-envelope through the live-event handler, skipping any envelope whose id was already present. Once the live state drifted - missed socket events, replacements applied at stale positions, ordering skew - the drift persisted until the sandbox slept, matching the corruption observed on staging (transcripts collapsing to the prompt plus latest answer, blank renders, steered messages out of order). _mergeAcpHistory now rebuilds the transcript from the fetched envelopes with the same loader, then carries over only messages the fetch does not cover yet (optimistic sends and unpersisted live events, matched by logical event id, clientMessageId, tool call id, or originating event timestamp). Every refetch is a convergence point to server truth, and an identical refetch keeps the previous references so nothing re-renders. The new steered-task regression suite includes a drift-healing case that fails against the previous incremental merge. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com>
…annel (#43) Editing one Slack auto-respond channel re-validated every configured channel and failed the whole save if any single one could not be resolved by name (e.g. a channel that was archived, renamed, or turned private). Users saw errors like "Could not resolve Slack channel #deepstrike-roo" while editing a completely different channel. Root cause was a lossy identity round-trip: the settings form hydrates each row's display name via conversations.info (lookup by ID, which still works for archived/renamed/private channels), but on save the server re-resolved that name via conversations.list (lookup by name, which excludes archived channels and misses private-not-member ones and can bail on rate limits). Any row that failed re-resolution set a field error and aborted the entire save before writing anything. Preserve the persisted channel ID through the form round-trip and use it as the resolution input for untouched rows. Resolving by ID short- circuits without a Slack lookup, so a stale channel elsewhere in the list can no longer block saving an edit to another row. The ID is dropped only when the user actually edits that row's channel, forcing a fresh name resolution. Mirrors how manager/coach channels already keep their persisted IDs when not being edited. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…worker (#119) Co-authored-by: Roomote <roomote@roocode.com>
Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Roomote <roomote@roocode.com>
…line release (#125) Co-authored-by: Roomote <roomote@roocode.com>
Co-authored-by: Roomote <roomote@roocode.com>
#127) Co-authored-by: Roomote <roomote@roocode.com>
Co-authored-by: Roomote <roomote@roocode.com>
…ng 15) (#130) Co-authored-by: Roomote <roomote@roocode.com>
Co-authored-by: Roomote <roomote@roocode.com>
…artifacts in the inference image (#129) Co-authored-by: Roomote <roomote@roocode.com>
…ilds (#137) The gate builds its own local images for the smoke test, so serializing it ahead of the build matrix only added its ~5 minutes to every publish. Gate the publish job instead: builds push untagged per-arch digests, and nothing is consumable until publish assembles the tagged manifests, so a failed gate still prevents any image from shipping. Cuts merge-to-nightly wall clock from ~12 to ~7 minutes. Co-authored-by: Roomote <roomote@roocode.com>
…#139) Self-review chat messages now say "I reviewed … on GitHub/GitLab/…" so people can tell where the review happened. Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com> Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Roomote <roomote@roomote.dev>
Sandbox logs do not survive the sandbox and Modal exposes none at all, so runtime facts worth a post-mortem keep dying with the machine. This adds a diagnostic rail on the existing task_run_events audit table: - a `diagnostic` run event type, recorded by workers through the existing sdk.taskRuns.recordEvent path (no schema change), - a worker-side recorder that is observer-only: fire-and-forget, never throws into the caller, caps every string, and scrubs token-shaped values and credential assignments before anything leaves the process, - a `tasks.runEvents` web tRPC reader so per-task events are queryable without database access. Nothing emits through the recorder yet; the OpenCode exit certificate lands separately on top of this rail. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
Re-reviewed the one new commit since the last review (#147 — "Address review findings on the diagnostic rail and death certificate"). The death-certificate false-positive is fixed: deliberate reconnect/restart/teardown kills route through
|
…pectedly (#145) When the OpenCode subprocess dies mid-task today, the worker silently reconnects and every fact about the death vanishes with the sandbox. The worker now stands witness: a bounded ring of the subprocess's last output lines is kept while it runs, and an exit while the task is not being cancelled records a durable diagnostic run event with the exit code, signal, uptime, output tail, and a memory snapshot taken at the instant of death, plus a Sentry capture for alerting. Exit code 137 versus a panic stack versus a clean exit is the difference between "killed for memory", "OpenCode bug", and "something else" — the distinction the last two investigations could not make. Collection cost is constant per output line, certification runs only on unexpected exits, and the callback is observer-only: its failures are logged and never touch the harness lifecycle. Output lines pass through the diagnostic recorder's secret scrubbing before persisting. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…payload kind (#134) Co-authored-by: Roomote <roomote@roocode.com>
…s, retention, and classification constraints (#136) Co-authored-by: Roomote <roomote@roocode.com>
…135) Co-authored-by: Roomote <roomote@roocode.com>
…icate (#147) * [Fix] Address review findings on the diagnostic rail and death certificate Review follow-up for #140 and #145, which merged before their bot reviews were read: - Deliberate harness terminations (reconnect, restart, teardown) are no longer certified as unexpected exits: ReconnectableHarness marks the subprocess before killing it, and certification skips marked exits, which also silences the Sentry alert that fired on every routine reconnect. - The death tail no longer depends on the startup URL wait leaving its line listeners attached: dedicated readers feed the ring for the whole subprocess lifetime. - The run-events reader returns the newest events under its limit (descending query, reversed to chronological), so a busy task cannot push the diagnostics it exists to surface out of the window. - A caller-supplied details.kind can no longer override the recorder's classification. - Hash-shaped values (git SHAs, digests) keep an 8-character prefix when redacted, preserving their evidentiary value without exposing credential-length material. - The memory reading is named and documented as what it is: the sandbox observed just after the exit, by the surviving worker process — the exit code/signal remains the authoritative OOM signal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Mark expected exits only while the subprocess is alive A crash surfaces as a disconnect first, and the disconnect cleanup then kills the already-dead process; marking it there raced the exit certification and could suppress the certificate for exactly the crash the rail exists to record. The mark now applies only to a process that is still alive at kill time, so deliberate teardowns stay quiet and self-inflicted deaths stay certified. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
Closing: this promote PR has head |
Promote v0.0.2
develop is ahead of main and product version
0.0.2is not tagged yet.v0.0.2and triggers the existing GHCRv*image publish (latestchannel).Changelog
0.0.2 (2026-07-10)
Patch changes