Conversation
When every configured search backend fails, the tool surfaced only the bare backend id list, leaving no path back to a working configuration. Append a configuration hint that names the keyed providers and their environment-variable aliases, the SearXNG base_url requirement, and the keyless firecrawl/bing routes. The hint is static text, so the existing no-private-details guarantee of the message is preserved and now pinned explicitly. Adapted from the Pinvou fork (Pinvou/CodeWhale 1fafee7), extended for the serply and tavily providers. Signed-off-by: asto18089 <asto18089@126.com>
…labels The <project_instructions source="..."> label carried the absolute path of the loaded AGENTS.md. The label sits inside the pinned system prompt, so loading an unchanged file from a moved or recased directory rewrote the label and emitted a spurious <context_update> history append, and it leaked the absolute project path into a provider-bound prompt label. The label now reports the file name only, via a shared project_instructions_source_label helper used by both ProjectContext::as_system_block and the /context report's rendered block (the report entry keeps the absolute path for operators). The repo-constitution block, which sits in the same pinned region and always resolves a fixed relative path, gets the same file-name convention; its locator stays available via constitution_source_path and /constitution. Directory identity is discoverable at runtime via the shell; the label is an origin tag, not a locator. Regression tests pin byte-identity of the instructions block for identical content loaded from two different directories and forbid absolute paths in both provider-bound labels. Adapted from the Pinvou fork (Pinvou/CodeWhale 102da17, PR #59) onto the current project_context layout. Co-authored-by: qiuYliangM <185303122+qiuYliangM@users.noreply.github.com> Signed-off-by: asto18089 <asto18089@126.com>
…_files The read-only scout brief commanded a `File` call with `action` `search_content`, but `File` is a hidden replay-only alias (`model_visible=false`): it never reaches a model-visible catalog, and the child step loop fails any call outside the child's policy-filtered catalog outright. The release-acceptance explore gate's first step therefore could not succeed; dispatch-by-alias only worked below the catalog gate (replay tests calling `registry.resolve` directly). Route the scout through the live surface instead: response 1 activates the deferred `grep_files` with one `tool_search` call, response 2 runs the same alternation search through `grep_files`, and response 3 returns the verdict. The step and token caps are unchanged; the evidence turn grows one small activation response. The leaf's explicit `allowed_tools: ["File"]` is dropped — the read-only lowering already scopes the leaf, and its alias-family intersection is what keeps `grep_files` discoverable. Guard both halves so neither side silently drifts again: a surface test pins the scout catalog to an active `tool_search` plus a deferred, searchable `grep_files` with no `File`; a behavioral test drives the activation through the real dispatch gate; and the fixture guard now pins the three-response contract and denies catalog-invisible tool names in the brief. Adapted from the Pinvou fork (Pinvou/CodeWhale 92427bd, PR #61). Signed-off-by: asto18089 <asto18089@126.com>
A host submitting a turn through the in-process engine (Op::SendMessage / Op::EditLastTurn) can attach an optional process-local correlation token, submission_id, and the engine echoes it verbatim on that turn's TurnStarted event. An embedder that defers submit-window actions (e.g. a stop replay) binds them to the turn that actually started instead of the first TurnStarted to arrive: every engine self-started turn (idle sub-agent continuation, background shell wake, goal continuation) and the composer shell command turn emit None, so their start can never be mistaken for the host's pending submission even when it overtakes it in the event stream. The change is additive and wire-compatible both ways: EventMsg::TurnStarted gains submission_id: Option<String> with serde(default) + skip_serializing_if, so old consumers parse new events and vice versa. The token stays on the internal TurnSpec only: the wire Op projection deliberately drops it and the durable-runtime submission path carries none, matching the in-process handle scope. The protocol-parity guard now asserts a stamped token crosses the Event -> wire projection verbatim; engine tests pin the echo contract, the edit replay's own token, and a real self-start staying None. Signed-off-by: asto18089 <asto18089@126.com>
…ight The journal records a tool call only at start and completion — nothing in between — so the background task's idle-progress deadline ran unopposed during any silent build, test suite, or MCP call and killed healthy work at the idle limit (120s by default). Track in-flight tool items by their journal id across the started/completed edges. While at least one tool is running, the turn loop refreshes the idle clock and publishes a supervisor-side ToolHeartbeat on the task-event channel, because the worker supervisor's own guard feeds from that channel and cannot see the journal-derived set. The heartbeat is liveness-only: it is excluded from persistence (it would rewrite the whole task record ~5x/s during a silent build) and from the visible timeline. The wall-time budget remains the backstop for a genuinely hung tool, and a turn with no in-flight tool still trips the idle deadline exactly as before. Disclosed gap: a background task mid-context-compaction is still invisible to the set (compaction emits no tool item and has no heartbeat of its own). Adapted from the Pinvou fork's timeout audit (Pinvou/CodeWhale d349f25, PR #63 review series). Signed-off-by: asto18089 <asto18089@126.com>
…iant Signed-off-by: asto18089 <asto18089@126.com>
…lope The image_analyze tool built its reqwest client with a single client-level 120-second timeout covering the whole call: connect, the multi-MB base64 upload, the full non-streaming vision generation, and the body read. A slow-but-healthy provider doing legitimate incremental work was killed at 120s with no distinction between "stalled" and "still working". reqwest's read_timeout is not a per-read idle bound for the request phase — its timer starts at send() and never resets until the response headers arrive — so an idle-read split cannot express this. Instead: - the client now bounds only the connect handshake (10s); - one tokio::time::timeout envelope (30 minutes, the same wall clock as engine streaming, STREAM_MAX_DURATION_SECS) wraps the request, all retry attempts, and the body decode as the sole total bound; - the timeout surfaces as ToolError::Timeout, which drives the existing TimedOut classification instead of a generic failure; - the envelope is scaled to 2s under cfg(test) so the new wiremock tests pin it without real time. Tests: a stalled provider hits the envelope and reports a timeout; a timely answer is returned intact. Full vision suite 59/0. Adapted from the Pinvou fork's timeout audit (Pinvou/CodeWhale d349f25 and its vision follow-ups, PR #63 review series). Signed-off-by: asto18089 <asto18089@126.com>
…ise the cap `execute_js_execution_tool` ran the interpreter as `timeout(120s, cmd.output())`: when the 120 seconds elapsed, tokio dropped the wait future WITHOUT killing the spawned child, so Node kept running detached — holding CPU, files, and pipe write-ends — while the tool reported a timeout. The 120s cap itself was also short for legitimate scripts (builds, report generation). Spawn the child under our ownership instead: it leads its own process group on Unix so the timeout kill reaches scripts that spawned their own children, `kill_on_drop` remains the backstop when the whole tool future is dropped (turn interrupt), and stdout/stderr are drained concurrently with the wait so a script blocked on a full pipe buffer still exits. On timeout the process group is SIGKILLed, the child is reaped, and the drain tasks are aborted. The cap is raised 120s → 600s. Tests pin the kill itself: a Node child that reports its pid and sleeps is verifiably dead after the timeout error, and a grandchild holding the pipes cannot make the call hang past the budget. Adapted from the Pinvou fork's timeout audit (Pinvou/CodeWhale d349f25, PR #63 review series). Signed-off-by: asto18089 <asto18089@126.com>
Hosted Lint failed only on this array formatting (backend.rs:852). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…dits Signed-off-by: CodeWhale Bot <bot@codewhale.net>
The Version drift job failed `scripts/check-contributor-credit.py`: @asto18089's commits need all three credit surfaces. CONTRIBUTORS.md and CHANGELOG.md already name them; web/lib/release-credits.ts did not. Local: credit check "11 contributor(s) ... credited on all three surfaces"; vitest public-copy + public-surface-contract 18 passed / 0 failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hosted Lint on #6737 failed only this import order (project_context.rs:27). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
#6738 failed all three OS test jobs at tools/workflow/mod.rs:11084: the acceptance test still required an explicit non-empty scout allowlist, which #6738 deliberately removed so the read-only catalog (tool_search -> deferred grep_files) scopes the scout. Assert that shape instead (`None`, pinned by scout_surface_keeps_tool_search_grep_files_activation_path). The scout's grep include and every role's file_scope named crates/tui/src/tools/workflow.rs, which does not exist (the module is tools/workflow/mod.rs), so the search could never see the owner it cites. Correct the path in the workflow, its js_authoring assertions and the parity doc, and assert every scoped file exists so the path cannot rot silently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…edits check-contributor-credit.py: every contributor credited on all three surfaces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…ntity Hosted Lint on #6799 failed check-runtime-contract-budget.py: the representative project-authority stage identity changed. That is #6737's intended change: project-instruction and constitution source labels become repository-relative instead of absolute paths. The stage also shrank 7617 -> 7605 bytes. Recorded with the script's documented `--update --allow-increase` from its own measurement; no other metric moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
#6759 already runs js_execution through process_tree::contained_output, so the PR's hand-rolled spawn, pipe drains and process-group kill resolve to that shared primitive (which also gives Windows its Job Object). Kept from the contributor: the 600 s budget (5 s under test) and both regression tests — the timed-out Node child is killed, not orphaned, and the timeout returns promptly while a grandchild holds the pipes. The contributor's commit 6372cbc is an unmodified parent, so #6743 lands as itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Brings in main through #6759 and 9507c4c, where #6743's unmodified head 6372cbc resolves onto main's contained js_execution with the contributor's 600 s budget and both regression tests. With this, #6743 lands as itself alongside #6736/#6737/#6738/#6740/#6742; @asto18089 is already on the unreleased credit line of this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
#6743's kill test polled with std::thread::sleep inside a current-thread tokio test. On main's contained_output path the timed-out child is SIGKILLed with its process group and reaped by tokio's orphan queue when the driver parks; the blocking poll never let it park, so the dead child stayed a zombie that kill(pid, 0) still reports (asto2 run: 10 passed, 1 failed). The poll now awaits, which also follows the blocking-call convention (#6149). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…s do The two #6743 tests printed their skip with eprintln!, which the tools module denies (clippy::print_stderr) and failed workspace Clippy. The module's existing Node-gated tests return silently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
The unmodified contributor head bf7df01 lands as itself. Its hosted Version drift failure was the credit check this branch already fixes; its hosted Linux PTY failure (launch_recent_click_then_enter_resumes...) is not reproduced locally (macOS: main 3/3, main+#6744 3/3), so this branch's exact-head Linux run is the arbiter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…ted field A runtime_threads test that reached main after #6744's base builds EngineEvent::TurnStarted without the new submission_id field (E0063 on the merged lib test build). A runtime turn is not a host submission, so the fixture carries None like every other runtime start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
#6740's worker_supervisor_honors_tool_heartbeats_during_silent_tools failed once on hosted Windows (#6799 run 36756608424: Failed instead of Completed, 0.955 s for a 360 ms script) after passing there on the previous head: a 30 ms heartbeat against the 150 ms short-test idle deadline starves on a loaded runner. The test now uses a 500 ms idle deadline and a 1.2 s silent window (40 x 30 ms), with a 5 s wall budget: the window still outlasts the deadline, so it fails if heartbeats stop counting as progress (see the controller receipt), but a stall must reach half a second to starve it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net>
This branch has not been deployed
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.
Lands seven of @asto18089's open PRs as themselves.
cw-land, the fixes their hosted checks needed are resolved here on an integration branch instead of on their branches.main. Nothing is harvested or rewritten.8dad7391556cf3732a88ec246ab063tool_search→ deferredgrep_files00db31a62b0823390658bf7df01a9TurnStartedechoes the host's submission id (additive, default-absent; every self-started turn carries none)6372cbc3fjs_executiongets a 600-second budget, and a timed-out interpreter is killed with everything it startedMaintainer fixes on top. Each one is a hosted failure from the original PRs:
style(search): the rustfmt array layout that failed fix(search): make the all-backends-unavailable error actionable #6736's Lint.style(context): thepub(crate) useimport order that failed fix(context): relativize project instruction and constitution source labels #6737's Lint.fix(workflow): fix(workflows): route the stopship scout through tool_search and grep_files #6738 failedstopship_acceptance_fixture_emits_role_gate_and_terminal_receiptson all three OSes.None).includeand every role'sfile_scopenamedcrates/tui/src/tools/workflow.rs, which does not exist (the module istools/workflow/mod.rs). The path is corrected in the workflow, thejs_authoringassertions and the parity doc.chore(credits): @asto18089 and @qiuYliangM added to the unreleased web credits. CONTRIBUTORS and CHANGELOG already name both, so the Version drift credit gate now passes.mainat568abae0, so credits compose with the current list.9507c4c73, then merged here with main636c700). fix(tools): shell job retention, output deltas, and child process lifetimes #6759 already runsjs_executionthroughprocess_tree::contained_output, so the PR's hand-rolled spawn, pipe drains and process-group kill resolve to that shared primitive, which also gives Windows its Job Object. Kept from the contributor: the 600-second budget (5 s under test) and both regression tests.test(js_execution): the contributor's kill test polled withstd::thread::sleepinside a current-thread tokio test. On the contained path the killed child is reaped by tokio's orphan queue when the driver parks, so the blocking poll kept a dead zombie visible tokill(pid, 0)(10 passed; 1 failed). The poll now awaits.Evidence (local, exact branch head, macOS arm64, governed build slots)
check-contributor-credit.py: 12 contributors, each credited on all three surfaces.18 passed; 0 failed.tools::web::backend,project_context,context_report,task_manager::,vision::tools, the stopship/scout tests):204 passed; 0 failed; 1 ignored.js_authoring:10 passed; 0 failed.workflows/stopship.workflow.js. The acceptance test then failed withexplore-runtime scopes a file that does not exist: crates/tui/src/tools/workflow.rs. The file was restored byte-exact, and the restored run passed.c1957a839(Node v26.10.0):tools::js_execution::11 passed; 0 failed.contained_outputwas replaced by a barecmd.output(). The run gave9 passed; 2 failed: fix(tools): shell job retention, output deltas, and child process lifetimes #6759'sdropped_js_execution_kills_the_interpreter_treeand the contributor'stimeout_kills_the_node_child_instead_of_orphaning_it. Byte-exact restore, then11 passed; 0 failed.cargo fmt --check,git diff --checkand the blocking-call budget (754 sites, within budget).10 passed; 1 failed), then twoeprintln!skips thatclippy::print_stderrrejects.Not in this PR:
Those PRs stay open as themselves.
No-Issue: contributor queue integration for #6736, #6737, #6738, #6740 and #6742; each PR carries its own motivation.
e129f2975(merged unmodified, thentest(runtime): a runtime_threads fixture that reached main after feat(engine): echo host submission id on TurnStarted #6744's base builtTurnStartedwithout the new field (E0063). It carriesNonelike every runtime start.)783 passed; 0 failed; 4 ignored. Protocol crate:1 passed; 0 failed.10 passed; 0 failed; 6 ignored. The scenario that failed on feat(engine): echo host submission id on TurnStarted #6744's old hosted Linux run passed 3/3 on main and 3/3 on main+feat(engine): echo host submission id on TurnStarted #6744 locally (macOS). This PR's exact-head Linux run is the arbiter.TurnStartedstopped echoing the token.turn_started_echoes_submission_id_and_self_starts_stay_nonefailed (0 passed; 1 failed). Byte-exact restore, then1 passed; 0 failed.cargo fmt --check,git diff --check, the changelog mirror, the blocking-call budget (754 sites) and the runtime-contract budget (55 metrics exact) all pass.🤖 Generated with Claude Code