diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a85368ab8..158abf027f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 from plugins stay on demand. Finishing an OAuth login reconnects just that server, and `/mcp reload` redials every server that is not `lazy` and reports how many are not connected out of the configured total. -- Running shell commands open an inspector with their output and status, and - `Alt+V` opens the newest running shell (#6931). +- Running shell commands open an inspector with their output and status. It + follows new output until you scroll back, and drops Stop once the command + ends. `Alt+V` opens the card you clicked, even after newer cards arrive or a + tool run collapses around it. `/jobs wait` and `/jobs poll` open the same + inspector instead of freezing the screen for up to 5 s, a shell row in the + work dock opens it too, and a task row opens `/task show` instead of failing + with "Job … not found" (#6931). +- In `/setup`, `u` and `d` act only on the working-agreement step. Pressed on + another step they no longer close the wizard and switch your agreement off. +- `/setup` no longer says "You're ready." when no model is connected; its last + step asks for a provider and lists the P and C keys it accepts. A rejected + API key's reason stays visible at narrow widths. +- First run with a local Ollama model continues to the trust question and the + ready screen instead of ending onboarding, and the next launch no longer + starts onboarding again. +- A turn that ended in failure reads as an error, live and after resume. Retry + notices stay in the transcript instead of flashing a red error that hid the + recovery. +- File edits show as patches with their change summary once. Tool status + words read `done`, `failed` and `loaded, not run` everywhere, and a tool + that only loaded no longer gets a done check. +- Delegated agents' cards name the tool they are running instead of + "Core tool ". +- Markdown: a line like `#6235 fixed it` is no longer a heading, headings + render inline code and emphasis, and tables draw one rule under the header + instead of one between every row. +- The approval card shows its field labels and description in your language in + every locale, not only Simplified Chinese. +- `/mode work` says "Switched to Work mode.", and `/zidong` says it switched to + Full Access. `/overview` and `/setup` call the mode Work. +- The language screen points to `/config locale --save`, the Korean + Never chip says it allows nothing, and the elevation dialog's Abort says it + skips only that tool call. +- Less work on the UI thread and less memory per turn: + - the context meter keeps its estimates for unchanged history; + - tool calls share the turn's history instead of copying it; + - compaction checks pressure with one pass; + - write_atomic sweeps a directory for stale temps at most hourly; + - the pet costs nothing while hidden. - `/resume`, `/load` and other session changes that cannot run yet now list what is still busy and how to stop it. - Sessions that ended without a clean exit show `interrupted` with their age @@ -72,6 +109,10 @@ launcher guidance. ### Added +- `/connect []` signs in to a model provider that a plugin adds, + inside the TUI, and `/disconnect ` removes that sign-in. + `/login` and `/logout` are for your Codewhale account only. Plugins that + ship a shell installer can be installed from the plugin view (#6950). - `codewhale auth claude` and `/auth claude` add Claude subscription sign-in to the existing Anthropic route, with protected owned credentials, refresh before requests, a provider-picker choice and local sign-out. API-key billing @@ -210,6 +251,60 @@ launcher guidance. ### Fixed +- Windows 10 1607 starts again. 0.10.1 stopped at load with 0xC0000139 + because `DeriveCapabilitySidsFromName` is missing there; it is now resolved + at runtime (#6953). +- `codewhale resume` no longer refuses a session whose saved history still + holds a raw sub-agent handoff (#6954). +- A saved session over 8 MiB can be resumed and forked again. Journal entries + off the current branch are archived instead of refusing the session (#6955). +- Snapshot restore and `/undo` work with older git, such as the 2.43 that + Ubuntu 24.04 ships. They failed there with "only one reference expected". +- Cancelling your own background shell job no longer reports it as finished + or starts a new model turn. Cancelling a job that had already exited keeps + its real exit status instead of reading "killed, exit 0". +- A shell command that moves to the background after 30 seconds shows the + same "keep running in /jobs" notice as `Ctrl+B`, and its card no longer + shows the instructions written for the model. +- `todo_write` returns a short receipt (counts and the item in progress) to + the model instead of repeating the whole list on every call. +- Goal usage counts the turn that completes, yields or blocks the goal, so + `tokens_used` and `time_used_seconds` no longer stay at 0. `update_goal` + accepts a progress estimate with `yield`. +- Waiting on a running shell job reports how long ago it last printed and + whether it is still compiling or already running tests or the program. + Stopping a job from `/jobs`, and the completion the model then receives, + say whether build artifacts already on disk survive the kill (#6944). +- A shell command that has printed nothing for a minute still reads as + running ("no output for 1m 05s"), keeps its Stop action and is reachable + through the Runtime API; only a job whose process is gone after a restart + is stale. `/jobs poll` and `/jobs stdin` no longer consume the output the + model has not read yet (#6931). +- `/constitution`: `ratify` checks the digest you reviewed in `suggestions`, + so a file that changed after your review is refused as documented; `preview` + shows the block exactly as the model receives it; messages no longer claim a + ratify or migrate moves the prompt-cache prefix; the setup wizard no longer + lists an authority order that contradicts the base prompt, and it caps your + own note so saving never cuts its end. The Simplified Chinese manager uses + the glossary term 宪章 throughout. +- The pet shows sub-agents while they run, and a finished one no longer stays + "working". Half-block pet sprites are drawn crisply instead of blurred. +- A provider's retry delay is honored when a 429 carries it in the body + instead of a `Retry-After` header (#6923). +- A Codewhale home reached through a symlink or Windows junction keeps saving + artifacts and compacting (#6947). +- A workflow gate that blocks its own role is rejected when the plan is + admitted instead of deadlocking the run (#6945). +- Auto-Review gives its guardian an output budget a reasoning model can think + inside. +- Skills are deduplicated across roots by file, ignored-key warnings are + grouped, in-workspace skill links are followed, and `doctor` warns about a + dead `always_load` pin or an unrecognized bundled skill. +- MCP servers reconnect when a session sync drops the eager connection pool. +- The shared pet owner exits after ten minutes with no client. +- Tool headers keep their clipped part visible at narrow widths, `/jobs` + prints plain exit codes and a three-line tail, and a collapsed tool output + shows a single hidden row instead of a "1 line omitted" marker. - ChatGPT sign-in omits the unsupported `originator` query parameter that caused an initial `invalid_authorize_request` rejection. PKCE, account binding and granted-scope validation remain in the same login flow @@ -298,6 +393,23 @@ launcher guidance. deadline set by its first unsaved event. Tool heartbeats and store polls no longer restart that wait, and heartbeats are kept in memory only. +### Known limits + +- Windows: when the previous app-server owner died without cleaning up, the + next start refuses with "Windows stale-owner recovery is not qualified" and + the stale publication has to be removed by hand. Unix recovers on its own + ([#6915](https://github.com/codewhale-hq/Codewhale/issues/6915)). +- Idle CPU has not been measured on FreeBSD or Linux for this release + ([#6728](https://github.com/codewhale-hq/Codewhale/issues/6728)). +- Models.dev prices with context tiers: a turn above a model's first tier can + be priced at its base rate. The bundled catalog has no tiered rows, so this + can only happen after a live models.dev refresh + ([#6396](https://github.com/codewhale-hq/Codewhale/issues/6396)). +- Shell commands run by delegated agents appear in `/jobs` and the work dock + with their owner, not in the agent's own detail view; named terminal + sessions live in the terminal dock + ([#6931](https://github.com/codewhale-hq/Codewhale/issues/6931)). + ### Maintenance - CI and test harness only, no change to the shipped binaries. The @@ -308,10 +420,11 @@ launcher guidance. ### Contributors -- **[@SparkofSpike](https://github.com/SparkofSpike)** — live network-policy updates and goal milestone hand-back ([#6928](https://github.com/codewhale-hq/Codewhale/pull/6928), [#6930](https://github.com/codewhale-hq/Codewhale/pull/6930)). +- **[@LIghtJUNction](https://github.com/LIghtJUNction)** — plugin shell install and in-TUI plugin OAuth sign-in ([#6950](https://github.com/codewhale-hq/Codewhale/pull/6950)). +- **[@SparkofSpike](https://github.com/SparkofSpike)** — live network-policy updates and goal milestone hand-back ([#6928](https://github.com/codewhale-hq/Codewhale/pull/6928), [#6930](https://github.com/codewhale-hq/Codewhale/pull/6930)), and a relocated Codewhale home ([#6947](https://github.com/codewhale-hq/Codewhale/issues/6947)). - **[@dajiaohuang](https://github.com/dajiaohuang)** — cache-write token accounting ([#6913](https://github.com/codewhale-hq/Codewhale/pull/6913)). - **[@gaord](https://github.com/gaord)** — embedder telemetry surface support ([#6916](https://github.com/codewhale-hq/Codewhale/pull/6916)). -- **[@Lstarsky0](https://github.com/Lstarsky0)** — localized profile replies ([#6919](https://github.com/codewhale-hq/Codewhale/pull/6919)). +- **[@Lstarsky0](https://github.com/Lstarsky0)** — localized profile replies ([#6919](https://github.com/codewhale-hq/Codewhale/pull/6919)) and workflow gates that block their own role ([#6952](https://github.com/codewhale-hq/Codewhale/pull/6952)). - **[@jayanthvee](https://github.com/jayanthvee)** — Windows npm launcher guidance ([#6906](https://github.com/codewhale-hq/Codewhale/pull/6906)). - **[@asto18089](https://github.com/asto18089)** — callback-window reference fix for longer browser sign-in waits ([#6865](https://github.com/codewhale-hq/Codewhale/issues/6865)). - **[@BX166](https://github.com/BX166)** — reported three provider failure modes measured on AICraft's own traffic: a cold model that reads as a dead connection, a listed model that fails on every call, and a response cut at the output ceiling that reports `stop` ([#6889](https://github.com/codewhale-hq/Codewhale/issues/6889)). diff --git a/Cargo.lock b/Cargo.lock index 48e4ae5b90..bcafb838c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1113,7 +1113,7 @@ dependencies = [ [[package]] name = "codewhale-ratatui" -version = "0.1.1" +version = "0.1.2" dependencies = [ "crossterm", "libc", diff --git a/crates/config/src/user_constitution.rs b/crates/config/src/user_constitution.rs index 2d70d0c594..ade188bf6f 100644 --- a/crates/config/src/user_constitution.rs +++ b/crates/config/src/user_constitution.rs @@ -43,10 +43,11 @@ //! silently. [`UserConstitution::migrate_file`] writes a backup first so //! [`UserConstitution::rollback_file`] can restore the pre-migration bytes. //! - **The prompt projection is byte-stable.** -//! [`UserConstitution::cache_projection`] returns exactly the bytes that enter -//! the cache-stable prompt prefix plus their digest and measures. Suggested -//! clauses, preserved unknown fields, and schema metadata are all outside it, -//! so recording advice never invalidates a prompt cache. +//! [`UserConstitution::cache_projection`] returns exactly the bytes the model +//! receives (as a session message at turn admission, outside the cache-stable +//! prompt prefix) plus their digest and measures. Suggested clauses, +//! preserved unknown fields, and schema metadata are all outside it, so +//! recording advice never changes what the model receives. use std::collections::BTreeMap; use std::fmt::Write; diff --git a/crates/localization/locales/ca.json b/crates/localization/locales/ca.json index ab14a8bf9d..d573c6b978 100644 --- a/crates/localization/locales/ca.json +++ b/crates/localization/locales/ca.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "S'ha enviat al porta-retalls del terminal (els terminals no ho confirmen)", "ClipboardCutKeptText": "S'ha enviat al porta-retalls del terminal; el text es manté perquè els terminals no confirmen les còpies", "ClipboardNothingToPaste": "No hi ha res per enganxar: el porta-retalls és buit o no s'ha pogut llegir", + "ClipboardCopyFailed": "Ha fallat la còpia al porta-retalls: {error}", "KbContextMenu": "Actua sobre el que hi ha sota el punter: copia, enganxa, obre els detalls o un file:line a l'editor, enfoca o atura un agent", "KbPointerScroll": "Desplaça la transcripció; sobre el redactor, mou el cursor línia a línia", "KbPointerClick": "Activa la fila, el xip o el bloc d'eina sota el punter", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " Presenta un pla i el progrés de tasques, després canvia a Act o Operate", "HomeGoalModeTip": "Seguiment d'objectius - Defineix /goal per perseguir objectius", "OnboardLanguageTitle": "Tria l'idioma", - "OnboardLanguageBlurb": "Tria l'idioma de la interfície. El pots canviar en qualsevol moment amb `/settings set locale `.", + "OnboardLanguageBlurb": "Tria l'idioma de la interfície. El pots canviar en qualsevol moment amb `/config locale --save`.", "OnboardProviderTitle": "Tria el teu proveïdor de models", "OnboardProviderBlurb": "Tria on s'executa el teu model. Els proveïdors allotjats necessiten una clau; els runtimes locals poden continuar sense.", "KimiCodePlanApiKeyHint": "Per als plans de membresia de Kimi Code, crea la clau vinculada al pla a {console}.", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "Aquest acord guia el comportament, no els permisos d'execució.", "SetupStepVerificationTitle": "Revisió", "SetupStepVerificationWhy": "Resumeix l'estat de Setup i mostra quins passos estan verificats, omesos o encara calen acció.", - "SetupCheckpointLayerOrder": "Ordre de capes: constitució inclosa -> constitució global d'usuari -> constitució del repo -> instruccions AGENTS/del projecte -> memòria/handoff -> petició actual.", "SetupCheckpointDoneBundled": "Punt de control de la constitució complet: s'usa la llei inclosa/per defecte.", "SetupCheckpointDoneGuided": "Constitució ratificada — la teva llei permanent s'ha desat. Esmena-la en qualsevol moment amb /constitution.", "SetupCheckpointDoneKept": "Constitució conservada — la teva llei existent continua vigent, sense canvis. Esmena-la en qualsevol moment amb /constitution.", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "Intenció: ", "ApprovalMoreLines": " … (+{count} línies)", "ApprovalAutoDeniedSession": "{tool} denegat automàticament: ja has denegat una sol·licitud coincident en aquest torn. Envia un missatge nou perquè se't torni a preguntar.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox denegat ", "ElevationTitleRequired": " Cal elevació del sandbox ", "ElevationFieldTool": " Eina: ", "ElevationFieldCmd": " Cmd: ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "fet", "ToolReceiptLinesSingular": "1 línia", "ToolReceiptLinesPlural": "{count} línies", + "TodoStatusPending": "pendent", + "TodoStatusInProgress": "en curs", + "TodoStatusCompleted": "completada", + "TodoStatusCancelled": "cancel·lada", "CmdVoiceDescription": "Commuta l'entrada de veu: grava veu i transcriu-la al compositor", "CmdVoiceSendDescription": "Commuta l'enviament per veu: digues \"send it\" per enviar", "CmdVoiceControlDescription": "Commuta el control per veu: dictat que coneix l'esborrany", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Permet o denega l'accés elevat per a '{tool}'", "NotificationDecisionWebHint": "Decideix aquí o al web.", "NotificationTurnFailed": "El torn ha fallat", - "NotificationProviderFallback": "S'ha canviat a {provider} (alternativa {position}/{total}) després d'un error recuperable del proveïdor.", + "NotificationProviderFallback": "S'ha canviat a {provider} (alternativa {position}/{total}), després d'un error recuperable del proveïdor.", "ApprovalNeverPostureBlocked": "S'ha bloquejat '{tool}': aquesta sessió no permet eines que requereixen aprovació.", "NotificationWebApproved": "Aprovat al web.", "NotificationWebDenied": "Denegat al web.", diff --git a/crates/localization/locales/de.json b/crates/localization/locales/de.json index 861ed824c8..d3abd66eb9 100644 --- a/crates/localization/locales/de.json +++ b/crates/localization/locales/de.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "An die Zwischenablage des Terminals gesendet (Terminals bestätigen das nicht)", "ClipboardCutKeptText": "An die Zwischenablage des Terminals gesendet; der Text bleibt stehen, weil Terminals Kopien nicht bestätigen", "ClipboardNothingToPaste": "Nichts einzufügen: Die Zwischenablage ist leer oder nicht lesbar", + "ClipboardCopyFailed": "Kopieren in die Zwischenablage fehlgeschlagen: {error}", "KbContextMenu": "Auf das Element unter dem Zeiger wirken: kopieren, einfügen, Details oder ein file:line im Editor öffnen, einen Agenten fokussieren oder stoppen", "KbPointerScroll": "Transkript scrollen; über dem Editor den Cursor zeilenweise bewegen", "KbPointerClick": "Zeile, Chip oder Werkzeugblock unter dem Zeiger aktivieren", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " Plan und To-do-Fortschritt vorlegen, dann zu Act oder Operate wechseln", "HomeGoalModeTip": "Zielverfolgung – /goal setzen, um Ziele zu verfolgen", "OnboardLanguageTitle": "Sprache wählen", - "OnboardLanguageBlurb": "Wähle die UI-Sprache. Du kannst sie jederzeit mit `/settings set locale ` ändern.", + "OnboardLanguageBlurb": "Wähle die UI-Sprache. Du kannst sie jederzeit mit `/config locale --save` ändern.", "OnboardProviderTitle": "Modellprovider wählen", "OnboardProviderBlurb": "Wähle, wo dein Modell läuft. Gehostete Provider brauchen einen Schlüssel; lokale Laufzeiten kommen ohne aus.", "KimiCodePlanApiKeyHint": "Für Kimi-Code-Mitgliedschaftspläne erstelle den plangebundenen Schlüssel unter {console}.", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "Diese Vereinbarung lenkt das Verhalten, nicht die Laufzeitberechtigungen.", "SetupStepVerificationTitle": "Überprüfung", "SetupStepVerificationWhy": "Fasst den Setup-Status zusammen und zeigt, welche Schritte verifiziert, übersprungen oder noch offen sind.", - "SetupCheckpointLayerOrder": "Ebenenreihenfolge: mitgelieferte Verfassung -> benutzer-globale Verfassung -> Repo-Verfassung -> AGENTS-/Projektanweisungen -> Memory/Handoff -> aktuelle Anfrage.", "SetupCheckpointDoneBundled": "Verfassungs-Checkpoint abgeschlossen: mitgeliefertes/Standard-Recht wird verwendet.", "SetupCheckpointDoneGuided": "Verfassung ratifiziert — dein geltendes Recht ist gespeichert. Jederzeit mit /constitution änderbar.", "SetupCheckpointDoneKept": "Verfassung beibehalten — dein bestehendes Recht gilt unverändert. Jederzeit mit /constitution änderbar.", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "Absicht: ", "ApprovalMoreLines": " … (+{count} Zeilen)", "ApprovalAutoDeniedSession": "Auto-abgelehnt {tool}: Sie haben eine passende Anfrage in dieser Runde bereits abgelehnt. Senden Sie eine neue Nachricht, um erneut gefragt zu werden.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox verweigert ", "ElevationTitleRequired": " Sandbox-Elevation erforderlich ", "ElevationFieldTool": " Tool: ", "ElevationFieldCmd": " Befehl: ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "fertig", "ToolReceiptLinesSingular": "1 Zeile", "ToolReceiptLinesPlural": "{count} Zeilen", + "TodoStatusPending": "ausstehend", + "TodoStatusInProgress": "in Arbeit", + "TodoStatusCompleted": "erledigt", + "TodoStatusCancelled": "abgebrochen", "CmdVoiceDescription": "Spracheingabe umschalten: Sprache aufnehmen und in den Composer transkribieren", "CmdVoiceSendDescription": "Sprach-Auto-Senden umschalten: \"send it\" sagen zum Absenden", "CmdVoiceControlDescription": "Sprachsteuerung umschalten: Diktat, das deinen Entwurf kennt", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Erlaube oder verweigere erweiterte Zugriffsrechte für '{tool}'", "NotificationDecisionWebHint": "Entscheide hier oder im Web.", "NotificationTurnFailed": "Turn fehlgeschlagen", - "NotificationProviderFallback": "Nach einem behebbaren Anbieterfehler zu {provider} gewechselt (Ausweichoption {position}/{total}).", + "NotificationProviderFallback": "Zu {provider} gewechselt (Ausweichoption {position}/{total}), nach einem behebbaren Anbieterfehler.", "ApprovalNeverPostureBlocked": "'{tool}' wurde blockiert: Diese Sitzung erlaubt keine Tools, die eine Genehmigung erfordern.", "NotificationWebApproved": "Im Web genehmigt.", "NotificationWebDenied": "Im Web abgelehnt.", diff --git a/crates/localization/locales/en.json b/crates/localization/locales/en.json index e7de6d0334..a985d33bd5 100644 --- a/crates/localization/locales/en.json +++ b/crates/localization/locales/en.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "Sent to the terminal clipboard (terminals do not confirm it)", "ClipboardCutKeptText": "Sent to the terminal clipboard; the text stays because terminals do not confirm copies", "ClipboardNothingToPaste": "Nothing to paste: the clipboard is empty or could not be read", + "ClipboardCopyFailed": "Clipboard copy failed: {error}", "KbContextMenu": "Act on what is under the pointer: copy, paste, open details or a file:line in your editor, focus or stop an agent", "KbPointerScroll": "Scroll the transcript; over the composer, move the cursor a line at a time", "KbPointerClick": "Activate the row, chip, or tool block under the pointer", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " Present a plan and To-do progress, then switch to Work or Operate", "HomeGoalModeTip": "Goal tracking — /goal pursues one objective", "OnboardLanguageTitle": "Choose your language", - "OnboardLanguageBlurb": "Pick the UI language — change it anytime with `/settings set locale `.", + "OnboardLanguageBlurb": "Pick the UI language — change it anytime with `/config locale --save`.", "OnboardProviderTitle": "Choose your model provider", "OnboardProviderBlurb": "Pick where your model runs. Hosted providers need a key; local ones don't.", "KimiCodePlanApiKeyHint": "For Kimi Code plans, create the linked key at {console}.", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "This agreement guides behavior, not runtime permissions.", "SetupStepVerificationTitle": "Review", "SetupStepVerificationWhy": "Summarize setup status and show which steps are verified, skipped, or still need action.", - "SetupCheckpointLayerOrder": "Layer order: bundled Constitution -> user-global constitution -> repo constitution -> AGENTS/project instructions -> memory/handoff -> current request.", "SetupCheckpointDoneBundled": "Constitution checkpoint complete: using bundled/default law.", "SetupCheckpointDoneGuided": "Constitution ratified — your standing law is saved. Amend anytime with /constitution.", "SetupCheckpointDoneKept": "Constitution kept — your existing law stands, unchanged. Amend anytime with /constitution.", @@ -1253,7 +1253,6 @@ "ApprovalIntentLabel": "Intent: ", "ApprovalMoreLines": " … (+{count} lines)", "ApprovalAutoDeniedSession": "Auto-denied {tool}: you denied a matching request earlier in this turn. Send a new message to be asked again.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox Denied ", "ElevationTitleRequired": " Sandbox Elevation Required ", "ElevationFieldTool": " Tool: ", "ElevationFieldCmd": " Cmd: ", @@ -1270,7 +1269,7 @@ "ElevationOptionNetworkDesc": "Retry with outbound network (downloads and HTTP)", "ElevationOptionWriteDesc": "Retry with a wider writable scope", "ElevationOptionFullAccessDesc": "Retry without sandbox limits; grants unrestricted filesystem and network access", - "ElevationOptionAbortDesc": "Cancel this run", + "ElevationOptionAbortDesc": "Skip only this tool call", "ContextAutoCompacting": "Making room in the conversation…", "ContextManualCompacting": "Compacting context…", "ContextCompactionQueued": "Making room is queued — it runs after this turn.", @@ -1334,9 +1333,13 @@ "ToolFamilyVerify": "verify", "ToolFamilyThink": "think", "ToolFamilyGeneric": "tool", - "ToolReceiptDone": "Done", + "ToolReceiptDone": "done", "ToolReceiptLinesSingular": "1 line", "ToolReceiptLinesPlural": "{count} lines", + "TodoStatusPending": "pending", + "TodoStatusInProgress": "in progress", + "TodoStatusCompleted": "completed", + "TodoStatusCancelled": "cancelled", "CmdVoiceDescription": "Dictate into the composer", "CmdVoiceSendDescription": "Toggle voice auto-send: say \"send it\" to submit", "CmdVoiceControlDescription": "Toggle voice control: dictation that knows your draft", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Allow or deny elevated access for '{tool}'", "NotificationDecisionWebHint": "Decide here or on the web.", "NotificationTurnFailed": "Turn failed", - "NotificationProviderFallback": "Switched to {provider} (fallback {position}/{total}) after a recoverable provider error.", + "NotificationProviderFallback": "Switched to {provider} (fallback {position}/{total}), after a recoverable provider error.", "ApprovalNeverPostureBlocked": "Blocked '{tool}': this session does not allow tools that require approval.", "NotificationWebApproved": "Approved on the web.", "NotificationWebDenied": "Denied on the web.", diff --git a/crates/localization/locales/es-419.json b/crates/localization/locales/es-419.json index 59860bc0cd..f3871c4109 100644 --- a/crates/localization/locales/es-419.json +++ b/crates/localization/locales/es-419.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "Enviado al portapapeles de la terminal (las terminales no lo confirman)", "ClipboardCutKeptText": "Enviado al portapapeles de la terminal; el texto se conserva porque las terminales no confirman las copias", "ClipboardNothingToPaste": "Nada para pegar: el portapapeles está vacío o no se pudo leer", + "ClipboardCopyFailed": "Falló la copia al portapapeles: {error}", "KbContextMenu": "Actuar sobre lo que está bajo el puntero: copiar, pegar, abrir detalles o un file:line en tu editor, enfocar o detener un agente", "KbPointerScroll": "Desplaza la transcripción; sobre el redactor, mueve el cursor línea por línea", "KbPointerClick": "Activa la fila, el chip o el bloque de herramienta bajo el puntero", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " Presenta el plan y luego cambia a Act u Operate", "HomeGoalModeTip": "Seguimiento de Goal - Usa /goal para seguir un objetivo persistente", "OnboardLanguageTitle": "Elige el idioma", - "OnboardLanguageBlurb": "Elige el idioma de la interfaz. Puedes cambiarlo en cualquier momento con `/settings set locale `.", + "OnboardLanguageBlurb": "Elige el idioma de la interfaz. Puedes cambiarlo en cualquier momento con `/config locale --save`.", "OnboardProviderTitle": "Elige tu proveedor de modelos", "OnboardProviderBlurb": "Elige dónde se ejecutará tu modelo. Los proveedores alojados necesitan una clave; los runtimes locales pueden continuar sin ella.", "KimiCodePlanApiKeyHint": "Para los planes de membresía de Kimi Code, crea la clave vinculada al plan en {console}.", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "Este acuerdo guía el comportamiento, no los permisos de ejecución.", "SetupStepVerificationTitle": "Revisión", "SetupStepVerificationWhy": "Resume el estado del setup y muestra qué pasos están verificados, saltados o aún necesitan acción.", - "SetupCheckpointLayerOrder": "Orden de capas: Constitution incluida -> constitution global de usuario -> constitution del repo -> instrucciones AGENTS/proyecto -> memoria/handoff -> solicitud actual.", "SetupCheckpointDoneBundled": "Checkpoint de constitution completo: usando ley incluida/predeterminada.", "SetupCheckpointDoneGuided": "Constitution ratificada — tu ley permanente fue guardada. Puedes modificarla en cualquier momento con /constitution.", "SetupCheckpointDoneKept": "Constitution conservada — tu ley existente queda sin cambios. Puedes modificarla en cualquier momento con /constitution.", @@ -1251,7 +1251,6 @@ "ApprovalIntentLabel": "Intención: ", "ApprovalMoreLines": " … (+{count} líneas)", "ApprovalAutoDeniedSession": "Se rechazó automáticamente {tool}: rechazaste antes una solicitud coincidente en este turno. Envía un mensaje nuevo para que se te vuelva a preguntar.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox Denegado ", "ElevationTitleRequired": " Elevación de Sandbox Requerida ", "ElevationFieldTool": " Herramienta: ", "ElevationFieldCmd": " Comando: ", @@ -1335,6 +1334,10 @@ "ToolReceiptDone": "listo", "ToolReceiptLinesSingular": "1 línea", "ToolReceiptLinesPlural": "{count} líneas", + "TodoStatusPending": "pendiente", + "TodoStatusInProgress": "en curso", + "TodoStatusCompleted": "completada", + "TodoStatusCancelled": "cancelada", "CmdVoiceDescription": "Alternar entrada de voz: grabar voz y transcribir a texto", "CmdVoiceSendDescription": "Alternar envío automático por voz: di \"send it\" para enviar", "CmdVoiceControlDescription": "Alternar control por voz: dictado que conoce tu borrador", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Permite o rechaza el acceso elevado para '{tool}'", "NotificationDecisionWebHint": "Decide aquí o en la web.", "NotificationTurnFailed": "El turno falló", - "NotificationProviderFallback": "Se cambió a {provider} (alternativa {position}/{total}) tras un error recuperable del proveedor.", + "NotificationProviderFallback": "Se cambió a {provider} (alternativa {position}/{total}), tras un error recuperable del proveedor.", "ApprovalNeverPostureBlocked": "Se bloqueó '{tool}': esta sesión no permite herramientas que requieren aprobación.", "NotificationWebApproved": "Aprobado en la web.", "NotificationWebDenied": "Rechazado en la web.", diff --git a/crates/localization/locales/fr.json b/crates/localization/locales/fr.json index b18bbb1940..82950899e0 100644 --- a/crates/localization/locales/fr.json +++ b/crates/localization/locales/fr.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "Envoyé au presse-papiers du terminal (les terminaux ne le confirment pas)", "ClipboardCutKeptText": "Envoyé au presse-papiers du terminal, le texte est conservé car les terminaux ne confirment pas les copies", "ClipboardNothingToPaste": "Rien à coller : le presse-papiers est vide ou illisible", + "ClipboardCopyFailed": "La copie dans le presse-papiers a échoué : {error}", "KbContextMenu": "Agir sur l'élément sous le pointeur : copier, coller, ouvrir les détails ou un file:line dans l'éditeur, cibler ou arrêter un agent", "KbPointerScroll": "Fait défiler la transcription ; sur le compositeur, déplace le curseur ligne par ligne", "KbPointerClick": "Active la ligne, la puce ou le bloc d'outil sous le pointeur", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " Présentez un plan et l'avancement des tâches, puis passez à Act ou Operate", "HomeGoalModeTip": "Suivi d'objectif — définissez /goal pour poursuivre des objectifs", "OnboardLanguageTitle": "Choisissez votre langue", - "OnboardLanguageBlurb": "Choisissez la langue de l'interface. Vous pouvez la changer à tout moment avec `/settings set locale `.", + "OnboardLanguageBlurb": "Choisissez la langue de l'interface. Vous pouvez la changer à tout moment avec `/config locale --save`.", "OnboardProviderTitle": "Choisissez votre fournisseur de modèles", "OnboardProviderBlurb": "Choisissez où votre modèle s'exécute. Les fournisseurs hébergés demandent une clé ; les runtimes locaux peuvent continuer sans.", "KimiCodePlanApiKeyHint": "Pour les plans d'adhésion Kimi Code, créez la clé liée au plan sur {console}.", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "Cet accord guide le comportement, pas les permissions d'exécution.", "SetupStepVerificationTitle": "Revue", "SetupStepVerificationWhy": "Résume le statut du setup et montre quelles étapes sont vérifiées, ignorées ou demandent encore une action.", - "SetupCheckpointLayerOrder": "Ordre des couches : Constitution intégrée -> constitution globale utilisateur -> constitution du repo -> instructions AGENTS/projet -> mémoire/handoff -> demande actuelle.", "SetupCheckpointDoneBundled": "Point de contrôle de la constitution terminé : loi intégrée/par défaut utilisée.", "SetupCheckpointDoneGuided": "Constitution ratifiée — votre loi permanente est enregistrée. Amendez-la à tout moment avec /constitution.", "SetupCheckpointDoneKept": "Constitution conservée — votre loi existante reste inchangée. Amendez-la à tout moment avec /constitution.", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "Intention : ", "ApprovalMoreLines": " … (+{count} lignes)", "ApprovalAutoDeniedSession": "{tool} refusé automatiquement : vous avez déjà refusé une demande correspondante pendant ce tour. Envoyez un nouveau message pour être à nouveau sollicité.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox refusé ", "ElevationTitleRequired": " Élévation du sandbox requise ", "ElevationFieldTool": " Outil : ", "ElevationFieldCmd": " Cmde : ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "terminé", "ToolReceiptLinesSingular": "1 ligne", "ToolReceiptLinesPlural": "{count} lignes", + "TodoStatusPending": "en attente", + "TodoStatusInProgress": "en cours", + "TodoStatusCompleted": "terminée", + "TodoStatusCancelled": "annulée", "CmdVoiceDescription": "Basculer l'entrée vocale : enregistrer la parole et transcrire dans le composeur", "CmdVoiceSendDescription": "Basculer l'envoi vocal : dites \"send it\" pour envoyer", "CmdVoiceControlDescription": "Basculer le contrôle vocal : dictée qui connaît le brouillon", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Autorisez ou refusez les droits d'accès supplémentaires pour « {tool} »", "NotificationDecisionWebHint": "Décidez ici ou sur le Web.", "NotificationTurnFailed": "Le tour a échoué", - "NotificationProviderFallback": "Passage à {provider} (solution de repli {position}/{total}) après une erreur récupérable du fournisseur.", + "NotificationProviderFallback": "Passage à {provider} (solution de repli {position}/{total}), après une erreur récupérable du fournisseur.", "ApprovalNeverPostureBlocked": "« {tool} » a été bloqué : cette session n'autorise pas les outils qui nécessitent une approbation.", "NotificationWebApproved": "Approuvé sur le Web.", "NotificationWebDenied": "Refusé sur le Web.", diff --git a/crates/localization/locales/hi.json b/crates/localization/locales/hi.json index 056fd76a0b..aff79fba96 100644 --- a/crates/localization/locales/hi.json +++ b/crates/localization/locales/hi.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "टर्मिनल क्लिपबोर्ड पर भेजा गया (टर्मिनल इसकी पुष्टि नहीं करते)", "ClipboardCutKeptText": "टर्मिनल क्लिपबोर्ड पर भेजा गया; टेक्स्ट रखा गया है क्योंकि टर्मिनल कॉपी की पुष्टि नहीं करते", "ClipboardNothingToPaste": "पेस्ट करने को कुछ नहीं: क्लिपबोर्ड खाली है या पढ़ा नहीं जा सका", + "ClipboardCopyFailed": "क्लिपबोर्ड पर कॉपी नहीं हो सकी: {error}", "KbContextMenu": "पॉइंटर के नीचे की चीज़ पर काम करें: कॉपी, पेस्ट, विवरण या एडिटर में file:line खोलें, एजेंट पर फ़ोकस करें या रोकें", "KbPointerScroll": "ट्रांसक्रिप्ट स्क्रॉल करें; कंपोज़र पर, कर्सर एक पंक्ति खिसकाएँ", "KbPointerClick": "पॉइंटर के नीचे की पंक्ति, चिप या टूल ब्लॉक सक्रिय करें", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " योजना और To-do प्रगति प्रस्तुत करें, फिर Act या Operate पर जाएँ", "HomeGoalModeTip": "गोल ट्रैकिंग - लक्ष्य के लिए /goal सेट करें", "OnboardLanguageTitle": "अपनी भाषा चुनें", - "OnboardLanguageBlurb": "UI भाषा चुनें। इसे कभी भी `/settings set locale ` से बदल सकते हैं।", + "OnboardLanguageBlurb": "UI भाषा चुनें। इसे कभी भी `/config locale --save` से बदल सकते हैं।", "OnboardProviderTitle": "अपना मॉडल प्रोवाइडर चुनें", "OnboardProviderBlurb": "चुनें कि आपका मॉडल कहाँ चलेगा। होस्टेड प्रोवाइडर को कुंजी चाहिए; लोकल रनटाइम बिना कुंजी के चल सकते हैं।", "KimiCodePlanApiKeyHint": "Kimi Code मेंबरशिप प्लान के लिए, {console} पर प्लान-लिंक्ड कुंजी बनाएँ।", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "यह समझौता व्यवहार का मार्गदर्शन करता है, रनटाइम अनुमतियों का नहीं।", "SetupStepVerificationTitle": "समीक्षा", "SetupStepVerificationWhy": "सेटअप स्थिति का सार दें और दिखाएँ कौन से चरण सत्यापित, छोड़े गए या कार्रवाई माँगते हैं।", - "SetupCheckpointLayerOrder": "परत क्रम: bundled संविधान -> उपयोगकर्ता-वैश्विक संविधान -> रिपो संविधान -> AGENTS/प्रोजेक्ट निर्देश -> मेमोरी/हैंडऑफ़ -> वर्तमान अनुरोध।", "SetupCheckpointDoneBundled": "संविधान चेकपॉइंट पूर्ण: bundled/डिफ़ॉल्ट कानून उपयोग में।", "SetupCheckpointDoneGuided": "संविधान अंगीकृत — आपका स्थायी कानून सहेजा गया। /constitution से कभी भी संशोधित करें।", "SetupCheckpointDoneKept": "संविधान बरकरार — आपका मौजूदा कानून अपरिवर्तित रहा। /constitution से कभी भी संशोधित करें।", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "इरादा: ", "ApprovalMoreLines": " … (+{count} पंक्तियाँ)", "ApprovalAutoDeniedSession": "स्वतः अस्वीकृत {tool}: आपने इसी टर्न में पहले मिलता-जुलता अनुरोध अस्वीकार किया था। फिर से पूछे जाने के लिए नया संदेश भेजें।", - "ElevationTitleSandboxDenied": " ⚠ सैंडबॉक्स अस्वीकृत ", "ElevationTitleRequired": " सैंडबॉक्स एलिवेशन आवश्यक ", "ElevationFieldTool": " टूल: ", "ElevationFieldCmd": " Cmd: ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "पूर्ण", "ToolReceiptLinesSingular": "1 पंक्ति", "ToolReceiptLinesPlural": "{count} पंक्तियाँ", + "TodoStatusPending": "लंबित", + "TodoStatusInProgress": "जारी", + "TodoStatusCompleted": "पूरा हुआ", + "TodoStatusCancelled": "रद्द", "CmdVoiceDescription": "वॉइस इनपुट टॉगल करें: बोली रिकॉर्ड कर कम्पोज़र में ट्रांसक्राइब करें", "CmdVoiceSendDescription": "वॉइस ऑटो-सेंड टॉगल करें: भेजने के लिए \"send it\" बोलें", "CmdVoiceControlDescription": "वॉइस कंट्रोल टॉगल करें: आपके ड्राफ़्ट को समझने वाला श्रुतलेख", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "'{tool}' के लिए अतिरिक्त पहुँच की अनुमति दें या अस्वीकार करें", "NotificationDecisionWebHint": "यहाँ या वेब पर फ़ैसला करें।", "NotificationTurnFailed": "टर्न विफल", - "NotificationProviderFallback": "प्रदाता की ठीक की जा सकने वाली त्रुटि के बाद {provider} पर स्विच किया गया (वैकल्पिक प्रदाता {position}/{total})।", + "NotificationProviderFallback": "{provider} पर स्विच किया गया (वैकल्पिक प्रदाता {position}/{total}); प्रदाता की त्रुटि ठीक की जा सकने वाली थी।", "ApprovalNeverPostureBlocked": "'{tool}' को ब्लॉक किया गया: इस सत्र में मंज़ूरी की ज़रूरत वाले टूल की अनुमति नहीं है।", "NotificationWebApproved": "वेब पर मंज़ूरी दी गई।", "NotificationWebDenied": "वेब पर अस्वीकार किया गया।", diff --git a/crates/localization/locales/id.json b/crates/localization/locales/id.json index 3ca9024157..4303fc65fc 100644 --- a/crates/localization/locales/id.json +++ b/crates/localization/locales/id.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "Dikirim ke papan klip terminal (terminal tidak mengonfirmasinya)", "ClipboardCutKeptText": "Dikirim ke papan klip terminal; teks tetap ada karena terminal tidak mengonfirmasi salinan", "ClipboardNothingToPaste": "Tidak ada yang bisa ditempel: papan klip kosong atau tidak dapat dibaca", + "ClipboardCopyFailed": "Penyalinan ke papan klip gagal: {error}", "KbContextMenu": "Bertindak pada yang ada di bawah penunjuk: salin, tempel, buka detail atau file:line di editor, fokus ke atau hentikan agen", "KbPointerScroll": "Gulir transkrip; di atas komposer, pindahkan kursor satu baris", "KbPointerClick": "Aktifkan baris, chip, atau blok alat di bawah penunjuk", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " Sajikan rencana dan progres To-do, lalu beralih ke Act atau Operate", "HomeGoalModeTip": "Pelacakan tujuan - Atur /goal untuk mengejar sasaran", "OnboardLanguageTitle": "Pilih bahasa Anda", - "OnboardLanguageBlurb": "Pilih bahasa UI. Anda dapat mengubahnya kapan saja dengan `/settings set locale `.", + "OnboardLanguageBlurb": "Pilih bahasa UI. Anda dapat mengubahnya kapan saja dengan `/config locale --save`.", "OnboardProviderTitle": "Pilih penyedia model Anda", "OnboardProviderBlurb": "Pilih tempat model Anda berjalan. Penyedia hosted memerlukan kunci; runtime lokal dapat lanjut tanpa kunci.", "KimiCodePlanApiKeyHint": "Untuk paket keanggotaan Kimi Code, buat kunci tertaut paket di {console}.", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "Kesepakatan ini memandu perilaku, bukan izin runtime.", "SetupStepVerificationTitle": "Tinjauan", "SetupStepVerificationWhy": "Ringkas status penyiapan dan tunjukkan langkah mana yang terverifikasi, dilewati, atau masih perlu tindakan.", - "SetupCheckpointLayerOrder": "Urutan lapisan: Konstitusi bawaan -> konstitusi global pengguna -> konstitusi repo -> instruksi AGENTS/proyek -> memori/handoff -> permintaan saat ini.", "SetupCheckpointDoneBundled": "Checkpoint konstitusi selesai: memakai hukum bawaan/default.", "SetupCheckpointDoneGuided": "Konstitusi diratifikasi — hukum tetap Anda tersimpan. Amendemen kapan saja dengan /constitution.", "SetupCheckpointDoneKept": "Konstitusi dipertahankan — hukum Anda yang ada tetap berlaku, tidak berubah. Amendemen kapan saja dengan /constitution.", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "Maksud: ", "ApprovalMoreLines": " … (+{count} baris)", "ApprovalAutoDeniedSession": "Ditolak otomatis {tool}: Anda sudah menolak permintaan yang cocok pada giliran ini. Kirim pesan baru agar ditanya lagi.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox Ditolak ", "ElevationTitleRequired": " Perlu Elevasi Sandbox ", "ElevationFieldTool": " Tool: ", "ElevationFieldCmd": " Cmd: ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "selesai", "ToolReceiptLinesSingular": "1 baris", "ToolReceiptLinesPlural": "{count} baris", + "TodoStatusPending": "tertunda", + "TodoStatusInProgress": "sedang dikerjakan", + "TodoStatusCompleted": "selesai", + "TodoStatusCancelled": "dibatalkan", "CmdVoiceDescription": "Alihkan input suara: rekam ucapan dan transkripsikan ke composer", "CmdVoiceSendDescription": "Alihkan kirim-otomatis suara: ucapkan \"send it\" untuk kirim", "CmdVoiceControlDescription": "Alihkan kontrol suara: dikte yang memahami draf Anda", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Izinkan atau tolak akses yang lebih luas untuk '{tool}'", "NotificationDecisionWebHint": "Tentukan pilihan di sini atau di web.", "NotificationTurnFailed": "Giliran gagal", - "NotificationProviderFallback": "Beralih ke {provider} (alternatif {position}/{total}) setelah terjadi kesalahan penyedia yang dapat dipulihkan.", + "NotificationProviderFallback": "Beralih ke {provider} (alternatif {position}/{total}), setelah terjadi kesalahan penyedia yang dapat dipulihkan.", "ApprovalNeverPostureBlocked": "'{tool}' diblokir: sesi ini tidak mengizinkan alat yang memerlukan persetujuan.", "NotificationWebApproved": "Disetujui di web.", "NotificationWebDenied": "Ditolak di web.", diff --git a/crates/localization/locales/ja.json b/crates/localization/locales/ja.json index ac3f5c2816..683bfa657e 100644 --- a/crates/localization/locales/ja.json +++ b/crates/localization/locales/ja.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "ターミナルのクリップボードに送信しました(ターミナルは受信を確認しません)", "ClipboardCutKeptText": "ターミナルのクリップボードに送信しました。ターミナルはコピーを確認しないため、テキストは残しています", "ClipboardNothingToPaste": "貼り付けるものがありません: クリップボードが空か、読み取れませんでした", + "ClipboardCopyFailed": "クリップボードへのコピーに失敗しました: {error}", "KbContextMenu": "ポインター下の対象を操作: コピー、貼り付け、詳細やエディターでの file:line を開く、エージェントへのフォーカスや停止", "KbPointerScroll": "トランスクリプトをスクロール。コンポーザー上ではカーソルを1行ずつ移動", "KbPointerClick": "ポインターの下にある行・チップ・ツールブロックを実行", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " 計画を提示してから Act または Operate へ", "HomeGoalModeTip": "Goal 追跡 - /goal <目標> で持続的な目標を追跡", "OnboardLanguageTitle": "言語を選択", - "OnboardLanguageBlurb": "UI 言語を選んでください。`/settings set locale ` でいつでも変更できます。", + "OnboardLanguageBlurb": "UI 言語を選んでください。`/config locale --save` でいつでも変更できます。", "OnboardProviderTitle": "モデルプロバイダーを選択", "OnboardProviderBlurb": "モデルの実行先を選びます。ホステッドプロバイダーにはキーが必要ですが、ローカルランタイムはキーなしで続行できます。", "KimiCodePlanApiKeyHint": "Kimi Code メンバーシッププランでは、{console} でプラン連携キーを作成します。", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "この作業合意は行動を導きますが、実行権限は変えません。", "SetupStepVerificationTitle": "レビュー", "SetupStepVerificationWhy": "セットアップ状態を要約し、確認済み、スキップ済み、または対応が必要なステップを表示します。", - "SetupCheckpointLayerOrder": "レイヤー順: 同梱 Constitution -> ユーザーグローバル constitution -> リポジトリ constitution -> AGENTS/プロジェクト指示 -> メモリ/引き継ぎ -> 現在の依頼。", "SetupCheckpointDoneBundled": "Constitution チェックポイント完了: 同梱/既定のルールを使用します。", "SetupCheckpointDoneGuided": "Constitution を承認しました。あなたの常設ルールを保存しました。いつでも /constitution で修正できます。", "SetupCheckpointDoneKept": "Constitution を維持しました。既存のルールは変更されません。いつでも /constitution で修正できます。", @@ -1251,7 +1251,6 @@ "ApprovalIntentLabel": "意図:", "ApprovalMoreLines": " … (+{count} 行)", "ApprovalAutoDeniedSession": "{tool} を自動的に拒否しました: このターンで一致するリクエストをすでに拒否しています。もう一度確認するには新しいメッセージを送信してください。", - "ElevationTitleSandboxDenied": " ⚠ サンドボックス拒否 ", "ElevationTitleRequired": " サンドボックス昇格 ", "ElevationFieldTool": " ツール:", "ElevationFieldCmd": " コマンド:", @@ -1335,6 +1334,10 @@ "ToolReceiptDone": "完了", "ToolReceiptLinesSingular": "1 行", "ToolReceiptLinesPlural": "{count} 行", + "TodoStatusPending": "未着手", + "TodoStatusInProgress": "進行中", + "TodoStatusCompleted": "完了", + "TodoStatusCancelled": "キャンセル済み", "CmdVoiceDescription": "音声入力の切替:音声を録音してテキストに変換", "CmdVoiceSendDescription": "音声自動送信の切替:「send it」と言うと送信", "CmdVoiceControlDescription": "音声コントロールの切替:下書きを踏まえたディクテーション", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "「{tool}」への追加権限を許可または拒否してください", "NotificationDecisionWebHint": "ここ、またはウェブで判断してください。", "NotificationTurnFailed": "ターン失敗", - "NotificationProviderFallback": "復旧可能なプロバイダーエラーのため、{provider} に切り替えました(代替先 {position}/{total})。", + "NotificationProviderFallback": "{provider} に切り替えました(代替先 {position}/{total})。復旧可能なプロバイダーエラーが発生しました。", "ApprovalNeverPostureBlocked": "「{tool}」をブロックしました。このセッションでは承認が必要なツールは許可されていません。", "NotificationWebApproved": "ウェブで承認されました。", "NotificationWebDenied": "ウェブで拒否されました。", diff --git a/crates/localization/locales/ko.json b/crates/localization/locales/ko.json index 62c543366e..cf67b17d69 100644 --- a/crates/localization/locales/ko.json +++ b/crates/localization/locales/ko.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "터미널 클립보드로 보냈습니다(터미널은 수신을 확인하지 않습니다)", "ClipboardCutKeptText": "터미널 클립보드로 보냈습니다. 터미널은 복사를 확인하지 않으므로 텍스트를 그대로 둡니다", "ClipboardNothingToPaste": "붙여넣을 내용이 없습니다: 클립보드가 비어 있거나 읽을 수 없습니다", + "ClipboardCopyFailed": "클립보드 복사에 실패했습니다: {error}", "KbContextMenu": "포인터 아래 대상에 대한 작업: 복사, 붙여넣기, 세부 정보 또는 편집기에서 file:line 열기, 에이전트 포커스 또는 중지", "KbPointerScroll": "트랜스크립트 스크롤. 작성창 위에서는 커서를 한 줄씩 이동", "KbPointerClick": "포인터 아래의 행, 칩 또는 도구 블록 실행", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " 계획과 할 일 진행 상황을 제시한 후 실행 또는 운영 모드로 전환", "HomeGoalModeTip": "목표 추적 - /goal <목표>로 목표를 설정하고 추진", "OnboardLanguageTitle": "언어를 선택하세요", - "OnboardLanguageBlurb": "UI 언어를 선택하세요. 언제든지 `/settings set locale <태그>`로 변경할 수 있습니다.", + "OnboardLanguageBlurb": "UI 언어를 선택하세요. 언제든지 `/config locale <태그> --save`로 변경할 수 있습니다.", "OnboardProviderTitle": "모델 프로바이더를 선택하세요", "OnboardProviderBlurb": "모델이 실행될 위치를 선택하세요. 호스팅 프로바이더는 키가 필요하지만 로컬 런타임은 키 없이 계속할 수 있습니다.", "KimiCodePlanApiKeyHint": "Kimi Code 멤버십 플랜은 {console}에서 플랜 연결 키를 만드세요.", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "이 작업 합의는 행동을 안내할 뿐, 실행 권한을 바꾸지 않습니다.", "SetupStepVerificationTitle": "검토", "SetupStepVerificationWhy": "설정 상태를 요약하고 어떤 단계가 확인됨, 건너뜀, 또는 아직 조치가 필요한지 표시합니다.", - "SetupCheckpointLayerOrder": "계층 순서: 내장 헌법 -> 사용자 전역 헌법 -> 저장소 헌법 -> AGENTS/프로젝트 지침 -> 메모리/인계 -> 현재 요청.", "SetupCheckpointDoneBundled": "헌법 체크포인트 완료: 내장/기본 규칙을 사용합니다.", "SetupCheckpointDoneGuided": "헌법이 승인되었습니다 — 상시 규칙이 저장되었습니다. /constitution으로 언제든지 수정할 수 있습니다.", "SetupCheckpointDoneKept": "헌법을 유지했습니다 — 기존 규칙이 변경 없이 그대로 적용됩니다. /constitution으로 언제든지 수정할 수 있습니다.", @@ -1253,7 +1253,6 @@ "ApprovalIntentLabel": "의도: ", "ApprovalMoreLines": " … (+{count}줄)", "ApprovalAutoDeniedSession": "{tool} 자동 거부: 이번 턴에서 일치하는 요청을 이미 거부했습니다. 다시 확인받으려면 새 메시지를 보내세요.", - "ElevationTitleSandboxDenied": " ⚠ 샌드박스 거부됨 ", "ElevationTitleRequired": " 샌드박스 권한 상승 필요 ", "ElevationFieldTool": " 도구: ", "ElevationFieldCmd": " 명령: ", @@ -1337,6 +1336,10 @@ "ToolReceiptDone": "완료", "ToolReceiptLinesSingular": "1줄", "ToolReceiptLinesPlural": "{count}줄", + "TodoStatusPending": "대기 중", + "TodoStatusInProgress": "진행 중", + "TodoStatusCompleted": "완료됨", + "TodoStatusCancelled": "취소됨", "CmdVoiceDescription": "음성 입력 전환: 음성을 녹음해 입력창에 받아쓰기", "CmdVoiceSendDescription": "음성 자동 전송 전환: \"send it\"이라고 말하면 전송", "CmdVoiceControlDescription": "음성 제어 전환: 초안을 이해하는 받아쓰기", @@ -1562,7 +1565,7 @@ "ChipPermissionAsk": "확인", "ChipPermissionAuto": "자동", "ChipPermissionFullAccess": "Full Access", - "ChipPermissionNever": "묻지 않음", + "ChipPermissionNever": "허용 안 함", "PermissionsChangedReceipt": "권한이 {label}(으)로 변경되었습니다", "FooterHintKeys": "단축키", "FooterHintOutput": "출력", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "'{tool}'의 추가 접근 권한을 허용하거나 거부하세요", "NotificationDecisionWebHint": "여기 또는 웹에서 결정하세요.", "NotificationTurnFailed": "턴 실패", - "NotificationProviderFallback": "복구 가능한 제공업체 오류가 발생하여 {provider}(으)로 전환했습니다(대체 경로 {position}/{total}).", + "NotificationProviderFallback": "{provider}(으)로 전환했습니다(대체 경로 {position}/{total}). 복구 가능한 제공업체 오류가 발생했습니다.", "ApprovalNeverPostureBlocked": "'{tool}'이(가) 차단되었습니다. 이 세션에서는 승인이 필요한 도구를 허용하지 않습니다.", "NotificationWebApproved": "웹에서 승인되었습니다.", "NotificationWebDenied": "웹에서 거부되었습니다.", diff --git a/crates/localization/locales/pt-BR.json b/crates/localization/locales/pt-BR.json index d749131f6e..b184ff8adf 100644 --- a/crates/localization/locales/pt-BR.json +++ b/crates/localization/locales/pt-BR.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "Enviado à área de transferência do terminal (terminais não confirmam)", "ClipboardCutKeptText": "Enviado à área de transferência do terminal; o texto foi mantido porque terminais não confirmam cópias", "ClipboardNothingToPaste": "Nada para colar: a área de transferência está vazia ou não pôde ser lida", + "ClipboardCopyFailed": "Falha ao copiar para a área de transferência: {error}", "KbContextMenu": "Agir sobre o que está sob o ponteiro: copiar, colar, abrir detalhes ou um file:line no editor, focar ou parar um agente", "KbPointerScroll": "Rola a transcrição; sobre o compositor, move o cursor linha a linha", "KbPointerClick": "Ativa a linha, o chip ou o bloco de ferramenta sob o ponteiro", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " Apresente o plano e depois mude para Act ou Operate", "HomeGoalModeTip": "Rastreamento de Goal - Use /goal para rastrear um objetivo persistente", "OnboardLanguageTitle": "Escolha o idioma", - "OnboardLanguageBlurb": "Escolha o idioma da interface. Você pode mudá-lo a qualquer momento com `/settings set locale `.", + "OnboardLanguageBlurb": "Escolha o idioma da interface. Você pode mudá-lo a qualquer momento com `/config locale --save`.", "OnboardProviderTitle": "Escolha seu provedor de modelos", "OnboardProviderBlurb": "Escolha onde o modelo será executado. Provedores hospedados precisam de chave; runtimes locais podem continuar sem uma.", "KimiCodePlanApiKeyHint": "Para planos de assinatura Kimi Code, crie a chave vinculada ao plano em {console}.", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "Este acordo orienta o comportamento, não as permissões de execução.", "SetupStepVerificationTitle": "Revisão", "SetupStepVerificationWhy": "Resume o status do setup e mostra quais etapas estão verificadas, puladas ou ainda precisam de ação.", - "SetupCheckpointLayerOrder": "Ordem de camadas: Constitution embutida -> constitution global do usuário -> constitution do repo -> instruções AGENTS/projeto -> memória/handoff -> pedido atual.", "SetupCheckpointDoneBundled": "Checkpoint da constitution completo: usando lei embutida/padrão.", "SetupCheckpointDoneGuided": "Constitution ratificada — sua lei permanente foi salva. Altere a qualquer momento com /constitution.", "SetupCheckpointDoneKept": "Constitution mantida — sua lei existente continua sem mudanças. Altere a qualquer momento com /constitution.", @@ -1251,7 +1251,6 @@ "ApprovalIntentLabel": "Intenção: ", "ApprovalMoreLines": " … (+{count} linhas)", "ApprovalAutoDeniedSession": "{tool} foi negado automaticamente: você negou uma solicitação correspondente antes neste turno. Envie uma nova mensagem para ser perguntado de novo.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox Negado ", "ElevationTitleRequired": " Elevação de Sandbox Necessária ", "ElevationFieldTool": " Ferramenta: ", "ElevationFieldCmd": " Comando: ", @@ -1335,6 +1334,10 @@ "ToolReceiptDone": "concluído", "ToolReceiptLinesSingular": "1 linha", "ToolReceiptLinesPlural": "{count} linhas", + "TodoStatusPending": "pendente", + "TodoStatusInProgress": "em andamento", + "TodoStatusCompleted": "concluída", + "TodoStatusCancelled": "cancelada", "CmdVoiceDescription": "Alternar entrada de voz: gravar fala e transcrever para texto", "CmdVoiceSendDescription": "Alternar envio por voz: diga \"send it\" para enviar", "CmdVoiceControlDescription": "Alternar controle por voz: ditado que conhece seu rascunho", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Permita ou negue acesso elevado para '{tool}'", "NotificationDecisionWebHint": "Decida aqui ou na web.", "NotificationTurnFailed": "O turno falhou", - "NotificationProviderFallback": "Alternado para {provider} (alternativa {position}/{total}) após um erro recuperável do provedor.", + "NotificationProviderFallback": "Alternado para {provider} (alternativa {position}/{total}), após um erro recuperável do provedor.", "ApprovalNeverPostureBlocked": "'{tool}' foi bloqueado: esta sessão não permite ferramentas que exigem aprovação.", "NotificationWebApproved": "Aprovado na web.", "NotificationWebDenied": "Negado na web.", diff --git a/crates/localization/locales/ru.json b/crates/localization/locales/ru.json index 4a0ed970dd..87d250a26f 100644 --- a/crates/localization/locales/ru.json +++ b/crates/localization/locales/ru.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "Отправлено в буфер обмена терминала (терминалы это не подтверждают)", "ClipboardCutKeptText": "Отправлено в буфер обмена терминала; текст оставлен, потому что терминалы не подтверждают копирование", "ClipboardNothingToPaste": "Нечего вставить: буфер обмена пуст или не читается", + "ClipboardCopyFailed": "Не удалось скопировать в буфер обмена: {error}", "KbContextMenu": "Действия с тем, что под указателем: копировать, вставить, открыть детали или file:line в редакторе, перейти к агенту или остановить его", "KbPointerScroll": "Прокручивает расшифровку; над полем ввода перемещает курсор построчно", "KbPointerClick": "Активирует строку, чип или блок инструмента под указателем", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " Представьте план и прогресс To-do, затем переключитесь в Act или Operate", "HomeGoalModeTip": "Отслеживание цели - задайте /goal для достижения целей", "OnboardLanguageTitle": "Выберите язык", - "OnboardLanguageBlurb": "Выберите язык интерфейса. Его можно сменить в любой момент командой `/settings set locale `.", + "OnboardLanguageBlurb": "Выберите язык интерфейса. Его можно сменить в любой момент командой `/config locale --save`.", "OnboardProviderTitle": "Выберите провайдера модели", "OnboardProviderBlurb": "Выберите, где работает модель. Облачным провайдерам нужен ключ; локальные среды могут работать без него.", "KimiCodePlanApiKeyHint": "Для планов подписки Kimi Code создайте ключ, привязанный к плану, на {console}.", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "Это соглашение направляет поведение, но не меняет разрешения среды выполнения.", "SetupStepVerificationTitle": "Проверка", "SetupStepVerificationWhy": "Сводка статуса настройки: какие шаги проверены, пропущены или ещё требуют действий.", - "SetupCheckpointLayerOrder": "Порядок слоёв: встроенная конституция -> глобальная конституция пользователя -> конституция репозитория -> инструкции AGENTS/проекта -> память/передача -> текущий запрос.", "SetupCheckpointDoneBundled": "Контрольная точка конституции пройдена: используется встроенный закон по умолчанию.", "SetupCheckpointDoneGuided": "Конституция утверждена — ваш постоянный закон сохранён. Изменить можно в любой момент через /constitution.", "SetupCheckpointDoneKept": "Конституция сохранена — ваш текущий закон остаётся без изменений. Изменить можно в любой момент через /constitution.", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "Намерение: ", "ApprovalMoreLines": " … (ещё {count} строк)", "ApprovalAutoDeniedSession": "{tool} отклонён автоматически: вы уже отклонили похожий запрос в этом ходе. Отправьте новое сообщение, чтобы вас спросили снова.", - "ElevationTitleSandboxDenied": " ⚠ Отказ песочницы ", "ElevationTitleRequired": " Требуется повышение прав песочницы ", "ElevationFieldTool": " Инструмент: ", "ElevationFieldCmd": " Команда: ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "готово", "ToolReceiptLinesSingular": "1 строка", "ToolReceiptLinesPlural": "{count} строк", + "TodoStatusPending": "ожидает", + "TodoStatusInProgress": "в работе", + "TodoStatusCompleted": "выполнено", + "TodoStatusCancelled": "отменено", "CmdVoiceDescription": "Вкл/выкл голосовой ввод: записать речь и транскрибировать в поле ввода", "CmdVoiceSendDescription": "Вкл/выкл автоотправку голосом: скажите \"send it\"", "CmdVoiceControlDescription": "Вкл/выкл голосовое управление: диктовка с учётом черновика", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Разрешите или отклоните расширенный доступ для '{tool}'", "NotificationDecisionWebHint": "Примите решение здесь или в веб-интерфейсе.", "NotificationTurnFailed": "Ход завершился с ошибкой", - "NotificationProviderFallback": "После устранимой ошибки провайдера выполнено переключение на {provider} (резервный вариант {position}/{total}).", + "NotificationProviderFallback": "Переключено на {provider} (резервный вариант {position}/{total}). Ошибка провайдера была устранимой.", "ApprovalNeverPostureBlocked": "'{tool}' заблокирован: в этом сеансе запрещены инструменты, требующие одобрения.", "NotificationWebApproved": "Одобрено в веб-интерфейсе.", "NotificationWebDenied": "Отклонено в веб-интерфейсе.", diff --git a/crates/localization/locales/uk.json b/crates/localization/locales/uk.json index 59d76d8be9..927fee9f18 100644 --- a/crates/localization/locales/uk.json +++ b/crates/localization/locales/uk.json @@ -799,6 +799,7 @@ "ClipboardSentToTerminal": "Надіслано до буфера обміну термінала (термінали цього не підтверджують)", "ClipboardCutKeptText": "Надіслано до буфера обміну термінала; текст залишено, бо термінали не підтверджують копіювання", "ClipboardNothingToPaste": "Нічого вставити: буфер обміну порожній або його не вдалося прочитати", + "ClipboardCopyFailed": "Не вдалося скопіювати до буфера обміну: {error}", "KbContextMenu": "Дії з тим, що під вказівником: копіювати, вставити, відкрити деталі або file:line у редакторі, перейти до агента чи зупинити його", "KbPointerScroll": "Прокручує розшифровку; над полем вводу переміщує курсор по рядках", "KbPointerClick": "Активує рядок, чип або блок інструмента під вказівником", @@ -914,7 +915,7 @@ "HomePlanModeChecklistTip": " Подайте план і прогрес To-do, потім перейдіть до Act або Operate", "HomeGoalModeTip": "Відстеження цілей - задайте /goal , щоб досягати цілей", "OnboardLanguageTitle": "Оберіть мову", - "OnboardLanguageBlurb": "Оберіть мову інтерфейсу. Її можна змінити будь-коли командою `/settings set locale `.", + "OnboardLanguageBlurb": "Оберіть мову інтерфейсу. Її можна змінити будь-коли командою `/config locale --save`.", "OnboardProviderTitle": "Оберіть провайдера моделі", "OnboardProviderBlurb": "Оберіть, де працюватиме модель. Хмарні провайдери потребують ключ; локальні середовища можуть працювати без нього.", "KimiCodePlanApiKeyHint": "Для планів підписки Kimi Code створіть прив'язаний до плану ключ на {console}.", @@ -1019,7 +1020,6 @@ "SetupStepConstitutionWhy": "Ця угода спрямовує поведінку, але не змінює дозволи середовища виконання.", "SetupStepVerificationTitle": "Огляд", "SetupStepVerificationWhy": "Підсумуйте стан налаштування та подивіться, які кроки перевірено, пропущено або які ще потребують дій.", - "SetupCheckpointLayerOrder": "Порядок шарів: вбудована конституція -> глобальна конституція користувача -> конституція репозиторію -> інструкції AGENTS/проєкту -> пам'ять/передача -> поточний запит.", "SetupCheckpointDoneBundled": "Контрольну точку конституції завершено: використовується вбудоване/типове право.", "SetupCheckpointDoneGuided": "Конституцію ратифіковано — ваше чинне право збережено. Змінюйте будь-коли через /constitution.", "SetupCheckpointDoneKept": "Конституцію залишено — ваше чинне право діє без змін. Змінюйте будь-коли через /constitution.", @@ -1230,7 +1230,6 @@ "ApprovalIntentLabel": "Намір: ", "ApprovalMoreLines": " … (+{count} рядків)", "ApprovalAutoDeniedSession": "Автоматично відхилено {tool}: ви вже відхилили подібний запит у цьому ході. Надішліть нове повідомлення, щоб вас запитали знову.", - "ElevationTitleSandboxDenied": " ⚠ Пісочниця відхилена ", "ElevationTitleRequired": " Потрібне підвищення прав пісочниці ", "ElevationFieldTool": " Інструмент: ", "ElevationFieldCmd": " Команда: ", @@ -1314,6 +1313,10 @@ "ToolReceiptDone": "готово", "ToolReceiptLinesSingular": "1 рядок", "ToolReceiptLinesPlural": "{count} рядків", + "TodoStatusPending": "очікує", + "TodoStatusInProgress": "у роботі", + "TodoStatusCompleted": "виконано", + "TodoStatusCancelled": "скасовано", "CmdVoiceDescription": "Перемкнути голосове введення: записати мовлення й транскрибувати в редактор", "CmdVoiceSendDescription": "Перемкнути автонадсилання голосом: скажіть \"send it\"", "CmdVoiceControlDescription": "Перемкнути голосове керування: диктування, що знає чернетку", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Дозвольте або відхиліть розширений доступ для '{tool}'", "NotificationDecisionWebHint": "Ухваліть рішення тут або у вебінтерфейсі.", "NotificationTurnFailed": "Хід завершився з помилкою", - "NotificationProviderFallback": "Після виправної помилки постачальника виконано перемикання на {provider} (резервний варіант {position}/{total}).", + "NotificationProviderFallback": "Перемкнено на {provider} (резервний варіант {position}/{total}). Помилка постачальника була виправною.", "ApprovalNeverPostureBlocked": "'{tool}' заблоковано: у цьому сеансі заборонені інструменти, що потребують схвалення.", "NotificationWebApproved": "Схвалено у вебінтерфейсі.", "NotificationWebDenied": "Відхилено у вебінтерфейсі.", diff --git a/crates/localization/locales/vi.json b/crates/localization/locales/vi.json index 95b1d195ed..24fdbce2f2 100644 --- a/crates/localization/locales/vi.json +++ b/crates/localization/locales/vi.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "Đã gửi tới bộ nhớ tạm của terminal (terminal không xác nhận)", "ClipboardCutKeptText": "Đã gửi tới bộ nhớ tạm của terminal; văn bản được giữ lại vì terminal không xác nhận việc sao chép", "ClipboardNothingToPaste": "Không có gì để dán: bộ nhớ tạm trống hoặc không đọc được", + "ClipboardCopyFailed": "Sao chép vào bộ nhớ tạm không thành công: {error}", "KbContextMenu": "Thao tác với thứ dưới con trỏ: sao chép, dán, mở chi tiết hoặc file:line trong trình soạn thảo, tập trung hoặc dừng tác tử", "KbPointerScroll": "Cuộn bản ghi; trên khung soạn thảo, di chuyển con trỏ từng dòng", "KbPointerClick": "Kích hoạt hàng, chip hoặc khối công cụ dưới con trỏ", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " Trình kế hoạch rồi chuyển sang Act hoặc Operate", "HomeGoalModeTip": "Theo dõi mục tiêu - Dùng /goal để đặt mục tiêu làm việc", "OnboardLanguageTitle": "Chọn ngôn ngữ của bạn", - "OnboardLanguageBlurb": "Chọn ngôn ngữ hiển thị. Bạn có thể thay đổi bất kỳ lúc nào bằng lệnh `/settings set locale `.", + "OnboardLanguageBlurb": "Chọn ngôn ngữ hiển thị. Bạn có thể thay đổi bất kỳ lúc nào bằng lệnh `/config locale --save`.", "OnboardProviderTitle": "Chọn nhà cung cấp mô hình", "OnboardProviderBlurb": "Chọn nơi mô hình chạy. Nhà cung cấp được lưu trữ cần khóa; runtime cục bộ có thể tiếp tục mà không cần khóa.", "KimiCodePlanApiKeyHint": "Với gói thành viên Kimi Code, hãy tạo khóa gắn với gói tại {console}.", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "Thỏa thuận này hướng dẫn hành vi, không đổi quyền thực thi.", "SetupStepVerificationTitle": "Xem lại", "SetupStepVerificationWhy": "Tóm tắt trạng thái setup và cho biết bước nào đã xác minh, đã bỏ qua hoặc còn cần hành động.", - "SetupCheckpointLayerOrder": "Thứ tự lớp: Constitution tích hợp -> constitution toàn cục của người dùng -> constitution repo -> chỉ dẫn AGENTS/dự án -> bộ nhớ/handoff -> yêu cầu hiện tại.", "SetupCheckpointDoneBundled": "Checkpoint constitution hoàn tất: dùng luật tích hợp/mặc định.", "SetupCheckpointDoneGuided": "Constitution đã được phê chuẩn — luật thường trực của bạn đã được lưu. Có thể sửa bất cứ lúc nào bằng /constitution.", "SetupCheckpointDoneKept": "Constitution được giữ nguyên — luật hiện có không đổi. Có thể sửa bất cứ lúc nào bằng /constitution.", @@ -1251,7 +1251,6 @@ "ApprovalIntentLabel": "Ý định: ", "ApprovalMoreLines": " … (+{count} dòng)", "ApprovalAutoDeniedSession": "Đã tự động từ chối {tool}: bạn đã từ chối một yêu cầu khớp trước đó trong lượt này. Hãy gửi tin nhắn mới để được hỏi lại.", - "ElevationTitleSandboxDenied": " ⚠ Sandbox Bị Từ Chối ", "ElevationTitleRequired": " Yêu Cầu Nâng Cấp Sandbox ", "ElevationFieldTool": " Công cụ: ", "ElevationFieldCmd": " Lệnh: ", @@ -1335,6 +1334,10 @@ "ToolReceiptDone": "xong", "ToolReceiptLinesSingular": "1 dòng", "ToolReceiptLinesPlural": "{count} dòng", + "TodoStatusPending": "đang chờ", + "TodoStatusInProgress": "đang thực hiện", + "TodoStatusCompleted": "đã hoàn tất", + "TodoStatusCancelled": "đã hủy", "CmdVoiceDescription": "Bật/tắt nhập liệu bằng giọng nói: ghi âm và chuyển thành văn bản", "CmdVoiceSendDescription": "Bật/tắt tự gửi bằng giọng nói: nói \"send it\" để gửi", "CmdVoiceControlDescription": "Bật/tắt điều khiển giọng nói: đọc chính tả hiểu bản nháp", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "Cho phép hoặc từ chối nâng quyền truy cập cho '{tool}'", "NotificationDecisionWebHint": "Đưa ra quyết định tại đây hoặc trên web.", "NotificationTurnFailed": "Lượt thất bại", - "NotificationProviderFallback": "Đã chuyển sang {provider} (phương án dự phòng {position}/{total}) sau lỗi có thể khôi phục của nhà cung cấp.", + "NotificationProviderFallback": "Đã chuyển sang {provider} (dự phòng {position}/{total}), sau lỗi có thể khôi phục của nhà cung cấp.", "ApprovalNeverPostureBlocked": "Đã chặn '{tool}': phiên này không cho phép các công cụ cần được chấp thuận.", "NotificationWebApproved": "Đã chấp thuận trên web.", "NotificationWebDenied": "Đã từ chối trên web.", diff --git a/crates/localization/locales/zh-Hans.json b/crates/localization/locales/zh-Hans.json index d1ea4ff2d0..c18ec87f0f 100644 --- a/crates/localization/locales/zh-Hans.json +++ b/crates/localization/locales/zh-Hans.json @@ -816,6 +816,7 @@ "ClipboardSentToTerminal": "已发送到终端剪贴板(终端不会确认)", "ClipboardCutKeptText": "已发送到终端剪贴板;由于终端不会确认复制,文本已保留", "ClipboardNothingToPaste": "没有可粘贴的内容:剪贴板为空或无法读取", + "ClipboardCopyFailed": "复制到剪贴板失败:{error}", "KbContextMenu": "对指针下的内容操作:复制、粘贴、打开详情或在编辑器中打开 file:line、聚焦或停止智能体", "KbPointerScroll": "滚动记录;在输入框上方逐行移动光标", "KbPointerClick": "激活指针下的行、标签或工具块", @@ -931,7 +932,7 @@ "HomePlanModeChecklistTip": " 提交计划和待办进度,然后切换到 Work 或 Operate", "HomeGoalModeTip": "Goal 跟踪 - 设置 /goal <目标> 以跟踪持久目标", "OnboardLanguageTitle": "选择语言", - "OnboardLanguageBlurb": "选择界面语言。可随时使用 `/settings set locale ` 修改。", + "OnboardLanguageBlurb": "选择界面语言。可随时使用 `/config locale --save` 修改。", "OnboardProviderTitle": "选择模型提供商", "OnboardProviderBlurb": "选择模型运行的位置。托管提供商需要密钥;本地运行时无需密钥即可继续。", "KimiCodePlanApiKeyHint": "对于 Kimi Code 会员计划,请在 {console} 创建与计划关联的密钥。", @@ -1042,7 +1043,6 @@ "SetupStepConstitutionWhy": "此 Codewhale 宪章是工作约定,只指导行为,不会更改运行时权限。", "SetupStepVerificationTitle": "复核", "SetupStepVerificationWhy": "汇总设置状态,并显示哪些步骤已验证、已跳过或仍需操作。", - "SetupCheckpointLayerOrder": "层级顺序:内置基础宪章 -> 用户全局宪章 -> 仓库宪章 -> AGENTS/项目说明 -> 记忆/交接 -> 当前请求。", "SetupCheckpointDoneBundled": "宪章检查点已完成:使用内置/默认宪章。", "SetupCheckpointDoneGuided": "宪章已确认并保存。可随时用 /constitution 修改。", "SetupCheckpointDoneKept": "已保留现有宪章,内容保持不变。可随时用 /constitution 修改。", @@ -1253,7 +1253,6 @@ "ApprovalIntentLabel": "意图: ", "ApprovalMoreLines": " … (还有 {count} 行)", "ApprovalAutoDeniedSession": "已自动拒绝 {tool}:本回合中已有匹配请求被你拒绝。若要重新询问,请发送新消息。", - "ElevationTitleSandboxDenied": " ⚠ 沙箱拒绝 ", "ElevationTitleRequired": " 沙箱提权 ", "ElevationFieldTool": " 工具: ", "ElevationFieldCmd": " 命令: ", @@ -1337,6 +1336,10 @@ "ToolReceiptDone": "完成", "ToolReceiptLinesSingular": "1 行", "ToolReceiptLinesPlural": "{count} 行", + "TodoStatusPending": "待处理", + "TodoStatusInProgress": "进行中", + "TodoStatusCompleted": "已完成", + "TodoStatusCancelled": "已取消", "CmdVoiceDescription": "切换语音输入:录制语音并转录为文字", "CmdVoiceSendDescription": "切换语音自动发送:说出「send it」即可提交", "CmdVoiceControlDescription": "切换语音控制:能理解你草稿内容的听写", @@ -2455,7 +2458,7 @@ "NotificationElevationNeeded": "请允许或拒绝为“{tool}”提升访问权限", "NotificationDecisionWebHint": "请在此处或网页上作出决定。", "NotificationTurnFailed": "本回合失败", - "NotificationProviderFallback": "提供商出现可恢复错误,已切换至 {provider}(备用选项 {position}/{total})。", + "NotificationProviderFallback": "已切换至 {provider}(备用选项 {position}/{total}),因提供商出现可恢复错误。", "ApprovalNeverPostureBlocked": "已阻止“{tool}”:此会话不允许使用需要批准的工具。", "NotificationWebApproved": "已在网页上批准。", "NotificationWebDenied": "已在网页上拒绝。", diff --git a/crates/localization/locales/zh-Hant.json b/crates/localization/locales/zh-Hant.json index e918eee753..c6f62ac6a9 100644 --- a/crates/localization/locales/zh-Hant.json +++ b/crates/localization/locales/zh-Hant.json @@ -814,6 +814,7 @@ "ClipboardSentToTerminal": "已傳送到終端機剪貼簿(終端機不會確認)", "ClipboardCutKeptText": "已傳送到終端機剪貼簿;由於終端機不會確認複製,文字已保留", "ClipboardNothingToPaste": "沒有可貼上的內容:剪貼簿為空或無法讀取", + "ClipboardCopyFailed": "複製到剪貼簿失敗:{error}", "KbContextMenu": "對指標下的內容操作:複製、貼上、開啟詳情或在編輯器中開啟 file:line、聚焦或停止代理", "KbPointerScroll": "捲動記錄;在輸入框上方逐行移動游標", "KbPointerClick": "啟動指標下的列、標籤或工具區塊", @@ -929,7 +930,7 @@ "HomePlanModeChecklistTip": " 提交計畫與待辦進度,然後切換到 Work 或 Operate", "HomeGoalModeTip": "Goal 跟蹤 - 設定 /goal <目標> 以跟蹤持久目標", "OnboardLanguageTitle": "選擇語言", - "OnboardLanguageBlurb": "選擇介面語言。可隨時使用 `/settings set locale ` 修改。", + "OnboardLanguageBlurb": "選擇介面語言。可隨時使用 `/config locale --save` 修改。", "OnboardProviderTitle": "選擇模型供應商", "OnboardProviderBlurb": "選擇模型執行的位置。託管供應商需要金鑰;本地執行階段無需金鑰即可繼續。", "KimiCodePlanApiKeyHint": "對於 Kimi Code 會員計畫,請在 {console} 建立與計畫關聯的金鑰。", @@ -1040,7 +1041,6 @@ "SetupStepConstitutionWhy": "此工作約定只引導行為,不會更改執行權限。", "SetupStepVerificationTitle": "檢視", "SetupStepVerificationWhy": "總結設定狀態,並顯示哪些步驟已驗證、已略過或仍需操作。", - "SetupCheckpointLayerOrder": "層級順序:內建基礎憲章 -> 使用者全域憲章 -> 儲存庫憲章 -> AGENTS/專案指示 -> 記憶/交接 -> 目前請求。", "SetupCheckpointDoneBundled": "憲章檢查點完成:使用內建/預設憲章。", "SetupCheckpointDoneGuided": "憲章已確認並儲存。可隨時用 /constitution 修訂。", "SetupCheckpointDoneKept": "已保留現有憲章,內容維持不變。可隨時用 /constitution 修訂。", @@ -1251,7 +1251,6 @@ "ApprovalIntentLabel": "意圖: ", "ApprovalMoreLines": " … (還有 {count} 行)", "ApprovalAutoDeniedSession": "已自動拒絕 {tool}:本回合中已有相符請求被你拒絕。若要重新詢問,請傳送新訊息。", - "ElevationTitleSandboxDenied": " ⚠ 沙箱拒絕 ", "ElevationTitleRequired": " 沙箱提權 ", "ElevationFieldTool": " 工具: ", "ElevationFieldCmd": " 指令: ", @@ -1335,6 +1334,10 @@ "ToolReceiptDone": "完成", "ToolReceiptLinesSingular": "1 行", "ToolReceiptLinesPlural": "{count} 行", + "TodoStatusPending": "待處理", + "TodoStatusInProgress": "進行中", + "TodoStatusCompleted": "已完成", + "TodoStatusCancelled": "已取消", "CmdVoiceDescription": "切換語音輸入:錄製語音並轉錄為文字", "CmdVoiceSendDescription": "切換語音自動傳送:說出「send it」即可提交", "CmdVoiceControlDescription": "切換語音控制:能理解你草稿內容的聽寫", @@ -2453,7 +2456,7 @@ "NotificationElevationNeeded": "請允許或拒絕為「{tool}」提升存取權限", "NotificationDecisionWebHint": "請在此處或網頁上作出決定。", "NotificationTurnFailed": "本回合失敗", - "NotificationProviderFallback": "供應商發生可復原的錯誤,已切換至 {provider}(備用選項 {position}/{total})。", + "NotificationProviderFallback": "已切換至 {provider}(備用選項 {position}/{total}),因供應商發生可復原的錯誤。", "ApprovalNeverPostureBlocked": "已封鎖「{tool}」:此工作階段不允許使用需要核准的工具。", "NotificationWebApproved": "已在網頁上核准。", "NotificationWebDenied": "已在網頁上拒絕。", diff --git a/crates/localization/src/lib.rs b/crates/localization/src/lib.rs index 49ad543ae1..efbd761dbf 100644 --- a/crates/localization/src/lib.rs +++ b/crates/localization/src/lib.rs @@ -1022,6 +1022,7 @@ pub enum MessageId { ClipboardCutKeptText, /// Paste found nothing: the clipboard read came back empty or failed. ClipboardNothingToPaste, + ClipboardCopyFailed, ComposerOversizedSubmitHeld, /// Short toast form of [`Self::ComposerOversizedSubmitHeld`]; the toast row /// sheds clauses to fit, so the full text goes to the transcript instead. @@ -1262,7 +1263,6 @@ pub enum MessageId { SetupStepConstitutionWhy, SetupStepVerificationTitle, SetupStepVerificationWhy, - SetupCheckpointLayerOrder, SetupCheckpointDoneBundled, SetupCheckpointDoneGuided, SetupCheckpointDoneKept, @@ -1502,7 +1502,6 @@ pub enum MessageId { ApprovalMoreLines, ApprovalAutoDeniedSession, // Sandbox elevation dialog. - ElevationTitleSandboxDenied, ElevationTitleRequired, ElevationFieldTool, ElevationFieldCmd, @@ -1590,6 +1589,10 @@ pub enum MessageId { ToolReceiptDone, ToolReceiptLinesSingular, ToolReceiptLinesPlural, + TodoStatusPending, + TodoStatusInProgress, + TodoStatusCompleted, + TodoStatusCancelled, // Voice commands (/voice, /voice-send, /voice-control) CmdVoiceDescription, CmdVoiceSendDescription, @@ -3658,6 +3661,7 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::ClipboardSentToTerminal, MessageId::ClipboardCutKeptText, MessageId::ClipboardNothingToPaste, + MessageId::ClipboardCopyFailed, MessageId::ComposerOversizedSubmitHeld, MessageId::ComposerOversizedSubmitHeldShort, MessageId::KbContextMenu, @@ -3888,7 +3892,6 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::SetupStepConstitutionWhy, MessageId::SetupStepVerificationTitle, MessageId::SetupStepVerificationWhy, - MessageId::SetupCheckpointLayerOrder, MessageId::SetupCheckpointDoneBundled, MessageId::SetupCheckpointDoneGuided, MessageId::SetupCheckpointDoneKept, @@ -4107,7 +4110,6 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::ApprovalIntentLabel, MessageId::ApprovalMoreLines, MessageId::ApprovalAutoDeniedSession, - MessageId::ElevationTitleSandboxDenied, MessageId::ElevationTitleRequired, MessageId::ElevationFieldTool, MessageId::ElevationFieldCmd, @@ -4191,6 +4193,10 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::ToolReceiptDone, MessageId::ToolReceiptLinesSingular, MessageId::ToolReceiptLinesPlural, + MessageId::TodoStatusPending, + MessageId::TodoStatusInProgress, + MessageId::TodoStatusCompleted, + MessageId::TodoStatusCancelled, MessageId::CmdVoiceDescription, MessageId::CmdVoiceSendDescription, MessageId::CmdVoiceControlDescription, diff --git a/crates/tui/CHANGELOG.md b/crates/tui/CHANGELOG.md index 9f0c7d6a17..316d86d45e 100644 --- a/crates/tui/CHANGELOG.md +++ b/crates/tui/CHANGELOG.md @@ -27,8 +27,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 from plugins stay on demand. Finishing an OAuth login reconnects just that server, and `/mcp reload` redials every server that is not `lazy` and reports how many are not connected out of the configured total. -- Running shell commands open an inspector with their output and status, and - `Alt+V` opens the newest running shell (#6931). +- Running shell commands open an inspector with their output and status. It + follows new output until you scroll back, and drops Stop once the command + ends. `Alt+V` opens the card you clicked, even after newer cards arrive or a + tool run collapses around it. `/jobs wait` and `/jobs poll` open the same + inspector instead of freezing the screen for up to 5 s, a shell row in the + work dock opens it too, and a task row opens `/task show` instead of failing + with "Job … not found" (#6931). +- In `/setup`, `u` and `d` act only on the working-agreement step. Pressed on + another step they no longer close the wizard and switch your agreement off. +- `/setup` no longer says "You're ready." when no model is connected; its last + step asks for a provider and lists the P and C keys it accepts. A rejected + API key's reason stays visible at narrow widths. +- First run with a local Ollama model continues to the trust question and the + ready screen instead of ending onboarding, and the next launch no longer + starts onboarding again. +- A turn that ended in failure reads as an error, live and after resume. Retry + notices stay in the transcript instead of flashing a red error that hid the + recovery. +- File edits show as patches with their change summary once. Tool status + words read `done`, `failed` and `loaded, not run` everywhere, and a tool + that only loaded no longer gets a done check. +- Delegated agents' cards name the tool they are running instead of + "Core tool ". +- Markdown: a line like `#6235 fixed it` is no longer a heading, headings + render inline code and emphasis, and tables draw one rule under the header + instead of one between every row. +- The approval card shows its field labels and description in your language in + every locale, not only Simplified Chinese. +- `/mode work` says "Switched to Work mode.", and `/zidong` says it switched to + Full Access. `/overview` and `/setup` call the mode Work. +- The language screen points to `/config locale --save`, the Korean + Never chip says it allows nothing, and the elevation dialog's Abort says it + skips only that tool call. +- Less work on the UI thread and less memory per turn: + - the context meter keeps its estimates for unchanged history; + - tool calls share the turn's history instead of copying it; + - compaction checks pressure with one pass; + - write_atomic sweeps a directory for stale temps at most hourly; + - the pet costs nothing while hidden. - `/resume`, `/load` and other session changes that cannot run yet now list what is still busy and how to stop it. - Sessions that ended without a clean exit show `interrupted` with their age @@ -72,6 +109,10 @@ launcher guidance. ### Added +- `/connect []` signs in to a model provider that a plugin adds, + inside the TUI, and `/disconnect ` removes that sign-in. + `/login` and `/logout` are for your Codewhale account only. Plugins that + ship a shell installer can be installed from the plugin view (#6950). - `codewhale auth claude` and `/auth claude` add Claude subscription sign-in to the existing Anthropic route, with protected owned credentials, refresh before requests, a provider-picker choice and local sign-out. API-key billing @@ -210,6 +251,60 @@ launcher guidance. ### Fixed +- Windows 10 1607 starts again. 0.10.1 stopped at load with 0xC0000139 + because `DeriveCapabilitySidsFromName` is missing there; it is now resolved + at runtime (#6953). +- `codewhale resume` no longer refuses a session whose saved history still + holds a raw sub-agent handoff (#6954). +- A saved session over 8 MiB can be resumed and forked again. Journal entries + off the current branch are archived instead of refusing the session (#6955). +- Snapshot restore and `/undo` work with older git, such as the 2.43 that + Ubuntu 24.04 ships. They failed there with "only one reference expected". +- Cancelling your own background shell job no longer reports it as finished + or starts a new model turn. Cancelling a job that had already exited keeps + its real exit status instead of reading "killed, exit 0". +- A shell command that moves to the background after 30 seconds shows the + same "keep running in /jobs" notice as `Ctrl+B`, and its card no longer + shows the instructions written for the model. +- `todo_write` returns a short receipt (counts and the item in progress) to + the model instead of repeating the whole list on every call. +- Goal usage counts the turn that completes, yields or blocks the goal, so + `tokens_used` and `time_used_seconds` no longer stay at 0. `update_goal` + accepts a progress estimate with `yield`. +- Waiting on a running shell job reports how long ago it last printed and + whether it is still compiling or already running tests or the program. + Stopping a job from `/jobs`, and the completion the model then receives, + say whether build artifacts already on disk survive the kill (#6944). +- A shell command that has printed nothing for a minute still reads as + running ("no output for 1m 05s"), keeps its Stop action and is reachable + through the Runtime API; only a job whose process is gone after a restart + is stale. `/jobs poll` and `/jobs stdin` no longer consume the output the + model has not read yet (#6931). +- `/constitution`: `ratify` checks the digest you reviewed in `suggestions`, + so a file that changed after your review is refused as documented; `preview` + shows the block exactly as the model receives it; messages no longer claim a + ratify or migrate moves the prompt-cache prefix; the setup wizard no longer + lists an authority order that contradicts the base prompt, and it caps your + own note so saving never cuts its end. The Simplified Chinese manager uses + the glossary term 宪章 throughout. +- The pet shows sub-agents while they run, and a finished one no longer stays + "working". Half-block pet sprites are drawn crisply instead of blurred. +- A provider's retry delay is honored when a 429 carries it in the body + instead of a `Retry-After` header (#6923). +- A Codewhale home reached through a symlink or Windows junction keeps saving + artifacts and compacting (#6947). +- A workflow gate that blocks its own role is rejected when the plan is + admitted instead of deadlocking the run (#6945). +- Auto-Review gives its guardian an output budget a reasoning model can think + inside. +- Skills are deduplicated across roots by file, ignored-key warnings are + grouped, in-workspace skill links are followed, and `doctor` warns about a + dead `always_load` pin or an unrecognized bundled skill. +- MCP servers reconnect when a session sync drops the eager connection pool. +- The shared pet owner exits after ten minutes with no client. +- Tool headers keep their clipped part visible at narrow widths, `/jobs` + prints plain exit codes and a three-line tail, and a collapsed tool output + shows a single hidden row instead of a "1 line omitted" marker. - ChatGPT sign-in omits the unsupported `originator` query parameter that caused an initial `invalid_authorize_request` rejection. PKCE, account binding and granted-scope validation remain in the same login flow @@ -298,6 +393,23 @@ launcher guidance. deadline set by its first unsaved event. Tool heartbeats and store polls no longer restart that wait, and heartbeats are kept in memory only. +### Known limits + +- Windows: when the previous app-server owner died without cleaning up, the + next start refuses with "Windows stale-owner recovery is not qualified" and + the stale publication has to be removed by hand. Unix recovers on its own + ([#6915](https://github.com/codewhale-hq/Codewhale/issues/6915)). +- Idle CPU has not been measured on FreeBSD or Linux for this release + ([#6728](https://github.com/codewhale-hq/Codewhale/issues/6728)). +- Models.dev prices with context tiers: a turn above a model's first tier can + be priced at its base rate. The bundled catalog has no tiered rows, so this + can only happen after a live models.dev refresh + ([#6396](https://github.com/codewhale-hq/Codewhale/issues/6396)). +- Shell commands run by delegated agents appear in `/jobs` and the work dock + with their owner, not in the agent's own detail view; named terminal + sessions live in the terminal dock + ([#6931](https://github.com/codewhale-hq/Codewhale/issues/6931)). + ### Maintenance - CI and test harness only, no change to the shipped binaries. The @@ -308,10 +420,11 @@ launcher guidance. ### Contributors -- **[@SparkofSpike](https://github.com/SparkofSpike)** — live network-policy updates and goal milestone hand-back ([#6928](https://github.com/codewhale-hq/Codewhale/pull/6928), [#6930](https://github.com/codewhale-hq/Codewhale/pull/6930)). +- **[@LIghtJUNction](https://github.com/LIghtJUNction)** — plugin shell install and in-TUI plugin OAuth sign-in ([#6950](https://github.com/codewhale-hq/Codewhale/pull/6950)). +- **[@SparkofSpike](https://github.com/SparkofSpike)** — live network-policy updates and goal milestone hand-back ([#6928](https://github.com/codewhale-hq/Codewhale/pull/6928), [#6930](https://github.com/codewhale-hq/Codewhale/pull/6930)), and a relocated Codewhale home ([#6947](https://github.com/codewhale-hq/Codewhale/issues/6947)). - **[@dajiaohuang](https://github.com/dajiaohuang)** — cache-write token accounting ([#6913](https://github.com/codewhale-hq/Codewhale/pull/6913)). - **[@gaord](https://github.com/gaord)** — embedder telemetry surface support ([#6916](https://github.com/codewhale-hq/Codewhale/pull/6916)). -- **[@Lstarsky0](https://github.com/Lstarsky0)** — localized profile replies ([#6919](https://github.com/codewhale-hq/Codewhale/pull/6919)). +- **[@Lstarsky0](https://github.com/Lstarsky0)** — localized profile replies ([#6919](https://github.com/codewhale-hq/Codewhale/pull/6919)) and workflow gates that block their own role ([#6952](https://github.com/codewhale-hq/Codewhale/pull/6952)). - **[@jayanthvee](https://github.com/jayanthvee)** — Windows npm launcher guidance ([#6906](https://github.com/codewhale-hq/Codewhale/pull/6906)). - **[@asto18089](https://github.com/asto18089)** — callback-window reference fix for longer browser sign-in waits ([#6865](https://github.com/codewhale-hq/Codewhale/issues/6865)). - **[@BX166](https://github.com/BX166)** — reported three provider failure modes measured on AICraft's own traffic: a cold model that reads as a dead connection, a listed model that fails on every call, and a response cut at the output ceiling that reports `stop` ([#6889](https://github.com/codewhale-hq/Codewhale/issues/6889)). diff --git a/crates/tui/Cargo.toml b/crates/tui/Cargo.toml index f91866fe1b..257da8502e 100644 --- a/crates/tui/Cargo.toml +++ b/crates/tui/Cargo.toml @@ -36,10 +36,11 @@ rusty-alloc = [] [lib] name = "codewhale_tui" path = "src/lib.rs" +doctest = false [dependencies] # Independent terminal kit, pinned and vendored for reproducible binary builds. -codewhale-ratatui = { path = "../../vendor/codewhale-ratatui", version = "0.1.1" } +codewhale-ratatui = { path = "../../vendor/codewhale-ratatui", version = "0.1.2" } codewhale-sanitize = { path = "../sanitize", version = "0.10.2" } codewhale-memory = { path = "../memory", version = "0.10.2" } ahash = "0.8" @@ -87,7 +88,6 @@ jsonwebtoken = { version = "10", default-features = false, features = ["aws_lc_r ratatui = { version = "=0.30.2", features = ["unstable-rendered-line-info"] } regex = "1.11" reqwest = { workspace = true, features = ["blocking", "stream", "form", "http2"] } -rusqlite.workspace = true rquickjs.workspace = true rmcp = { version = "3.2.0", default-features = false, features = ["auth", "client"] } rustls.workspace = true @@ -103,7 +103,6 @@ syntect = { version = "5.2", default-features = false, features = ["default-synt serde.workspace = true serde_json = { workspace = true, features = ["preserve_order", "raw_value"] } yaml-rust2 = { workspace = true } -schemars = { version = "1.2.1", features = ["derive", "preserve_order"] } shellexpand = "3" # Grammar-exact Rust parsing for the post-edit syntax gate (#6204). `syn` is # already in the lockfile as a proc-macro build dependency; this reuses that @@ -172,6 +171,8 @@ wiremock = "0.6" tiny_http = "0.12" pretty_assertions = "1.4" rio-vt = "0.5.1" +rusqlite.workspace = true +schemars = { version = "1.2.1", features = ["derive", "preserve_order"] } tokio-tungstenite = "0.30" [target.'cfg(unix)'.dependencies] diff --git a/crates/tui/src/commands/groups/config/config.rs b/crates/tui/src/commands/groups/config/config.rs index 85d6719747..73555a3195 100644 --- a/crates/tui/src/commands/groups/config/config.rs +++ b/crates/tui/src/commands/groups/config/config.rs @@ -18,7 +18,9 @@ use crate::config_persistence::{ }; use crate::reasoning_preference::ReasoningEffort; use crate::settings::Settings; -use crate::tui::app::{App, AppAction, OnboardingState, ScreenMode, SettingSelection, VimMode}; +use crate::tui::app::{ + App, AppAction, AppModeUi, OnboardingState, ScreenMode, SettingSelection, VimMode, +}; use anyhow::Result; use codewhale_config::AppMode; use codewhale_execpolicy::ApprovalMode; @@ -2429,7 +2431,7 @@ pub fn set_config_value(app: &mut App, key: &str, value: &str, persist: bool) -> }; app.set_agent_shell_access(enabled); let mode_hint = if enabled { - " Act mode will expose shell on the next turn with approval gating. Full Access (Shift+Tab) also enables shell and auto-approves." + " Work mode will expose shell on the next turn with approval gating. Full Access (Shift+Tab) also enables shell and auto-approves." } else { " Shell tools will be hidden on the next turn. Re-enable with `/config allow_shell true`." }; @@ -3081,7 +3083,7 @@ fn mode_selection(app: &mut App, arg: &str) -> CommandResult { CommandResult::message(message) } } - None => CommandResult::error("Usage: /mode [act|agent|plan|operate|1|2|3]"), + None => CommandResult::error(format!("Usage: {}", super::MODE_INFO.usage)), } } @@ -3099,7 +3101,13 @@ pub fn switch_mode(app: &mut App, mode: AppMode) -> String { /// written nothing. fn switch_mode_with_status(app: &mut App, mode: AppMode) -> (String, bool) { match app.select_mode(mode) { - SettingSelection::Changed => (format!("Switched to {} mode.", mode.display_name()), true), + SettingSelection::Changed => ( + format!( + "Switched to {} mode.", + mode.display_name_localized(app.ui_locale) + ), + true, + ), SettingSelection::PersistedSame => (app.mode_startup_default_receipt(mode), false), SettingSelection::Refused => ( app.setting_locked_message(MessageId::SettingSubjectMode), @@ -3108,12 +3116,15 @@ fn switch_mode_with_status(app: &mut App, mode: AppMode) -> (String, bool) { } } -/// Status for the legacy YOLO alias: user-facing copy says Act, because the -/// alias is invisible Act + Full Access. +/// Status for the legacy YOLO alias: user-facing copy names Full Access (Work), +/// because the alias is invisible Work + Full Access. fn switch_yolo_compat_with_status(app: &mut App) -> (String, bool) { match app.select_yolo_compat() { SettingSelection::Changed => ( - format!("Switched to {} mode.", AppMode::Agent.display_name()), + format!( + "Switched to {}.", + tr(app.ui_locale, MessageId::HotbarActionModeYoloName) + ), true, ), SettingSelection::PersistedSame => { @@ -4128,8 +4139,13 @@ mod tests { // user settings on the host machine. let _ = mode(&mut app, Some("agent")); let result = mode(&mut app, Some("yolo")); - // YOLO is invisible Act+Bypass shorthand — user-facing copy says Act. - assert!(result.message.unwrap().contains("Switched to Act mode")); + // YOLO is invisible Work+Bypass shorthand — user-facing copy names Full Access (Work). + assert!( + result + .message + .unwrap() + .contains("Switched to Full Access (Work)") + ); assert_eq!(result.action, Some(AppAction::ModeChanged(AppMode::Agent))); assert!(app.allow_shell); assert!(app.trust_mode); @@ -4857,7 +4873,7 @@ mod tests { assert!(msg.contains("allow_shell = true")); assert!(msg.contains("session only")); - assert!(msg.contains("Act mode")); + assert!(msg.contains("Work mode")); assert!(msg.contains("approval gating")); assert!(msg.contains("next turn")); assert!(msg.contains("Full Access (Shift+Tab) also enables shell and auto-approves")); @@ -4880,7 +4896,7 @@ mod tests { assert_eq!( msg, format!( - "allow_shell = true (saved to {}). Act mode will expose shell on the next turn with approval gating. Full Access (Shift+Tab) also enables shell and auto-approves.", + "allow_shell = true (saved to {}). Work mode will expose shell on the next turn with approval gating. Full Access (Shift+Tab) also enables shell and auto-approves.", config_path.display() ) ); diff --git a/crates/tui/src/commands/groups/config/mod.rs b/crates/tui/src/commands/groups/config/mod.rs index 65f41bc896..8d3db263ce 100644 --- a/crates/tui/src/commands/groups/config/mod.rs +++ b/crates/tui/src/commands/groups/config/mod.rs @@ -106,7 +106,7 @@ static STATUSLINE_INFO: CommandInfo = CommandInfo { static MODE_INFO: CommandInfo = CommandInfo { name: "mode", aliases: &["jihua", "zidong"], - usage: "/mode [act|plan|operate|1|2|3]", + usage: "/mode [work|plan|operate|1|2|3]", description_id: MessageId::CmdModeDescription, }; static FULLSCREEN_INFO: CommandInfo = CommandInfo { diff --git a/crates/tui/src/commands/groups/core/constitution.rs b/crates/tui/src/commands/groups/core/constitution.rs index 0a712ec26d..c611d9af86 100644 --- a/crates/tui/src/commands/groups/core/constitution.rs +++ b/crates/tui/src/commands/groups/core/constitution.rs @@ -91,7 +91,15 @@ impl RegisterCommand for ConstitutionCmd { .split_whitespace() .map(str::to_string) .collect(); - CommandResult::message(ratify_text(app.ui_locale, &ids)) + let (message, ratified) = ratify_text( + app.ui_locale, + app.constitution_reviewed_digest.as_deref(), + &ids, + ); + if ratified.is_some() { + app.constitution_reviewed_digest = ratified; + } + CommandResult::message(message) } Some("help") => CommandResult::message(help_text(app.ui_locale)), Some(other) => CommandResult::error(format!( @@ -151,16 +159,18 @@ fn open_explanation(app: &mut App) { /// because unratified model advice is not law. fn open_suggestions(app: &mut App) { let locale = app.ui_locale; - let text = suggestions_text(locale); + let (text, reviewed) = suggestions_text(locale); + app.constitution_reviewed_digest = reviewed; open_pager(app, suggestions_title(locale), &text); } -fn suggestions_text(locale: Locale) -> String { +fn suggestions_text(locale: Locale) -> (String, Option) { let UserConstitutionStatus::Loaded { constitution, .. } = load_user_constitution() else { - return match locale { - Locale::ZhHans => "没有可供审阅的结构化用户全局协作准则。".to_string(), + let text = match locale { + Locale::ZhHans => "没有可供审阅的结构化用户全局宪章。".to_string(), _ => "No structured user-global constitution is available to review.".to_string(), }; + return (text, None); }; let digest = constitution.cache_projection().digest; let suggested: Vec<_> = constitution.suggested_clauses().collect(); @@ -203,62 +213,82 @@ fn suggestions_text(locale: Locale) -> String { } } } - out + (out, Some(digest)) } -/// Explicit ratification (#3930). Fails closed: it re-reads the live file, -/// hands the live digest back to [`UserConstitution::ratify`], and persists only -/// when the clause set is exactly what the user named. -fn ratify_text(locale: Locale, ids: &[String]) -> String { +/// Explicit ratification (#3930). Fails closed: it hands the digest the user +/// reviewed in `/constitution suggestions` to [`UserConstitution::ratify`], +/// which refuses when the live file has moved since, and persists only when the +/// clause set is exactly what the user named. +fn ratify_text(locale: Locale, reviewed: Option<&str>, ids: &[String]) -> (String, Option) { if ids.is_empty() { - return match locale { + let text = match locale { Locale::ZhHans => { "用法:/constitution ratify [...]。先用 /constitution suggestions 查看待批准条款。" .to_string() } _ => "Usage: /constitution ratify [...]. Run /constitution suggestions first to see what is pending.".to_string(), }; + return (text, None); } let (path, constitution) = match load_user_constitution() { UserConstitutionStatus::Loaded { path, constitution } => (path, constitution), _ => { - return match locale { - Locale::ZhHans => "没有可批准的结构化用户全局协作准则。".to_string(), + let text = match locale { + Locale::ZhHans => "没有可批准的结构化用户全局宪章。".to_string(), _ => "There is no structured user-global constitution to ratify.".to_string(), }; + return (text, None); } }; - let digest = constitution.cache_projection().digest; - match constitution.ratify(&digest, ids, None) { - Err(err) => match locale { - Locale::ZhHans => format!("未批准任何条款:{err}"), - _ => format!("Nothing was ratified: {err}"), - }, - Ok(ratification) => match ratification.constitution.save_to(&path) { - Err(err) => match locale { - Locale::ZhHans => format!("批准已计算但保存失败,文件未更改:{err:#}"), - _ => format!( - "Ratification was computed but could not be saved; the file is unchanged: {err:#}" - ), - }, - Ok(()) => match locale { - Locale::ZhHans => format!( - "已批准 {} 条:{}\n摘要 {} → {}\n这些条款现在会注入模型;提示词缓存前缀已随之变化。", - ratification.accepted_clause_ids.len(), - ratification.accepted_clause_ids.join(", "), - ratification.before_digest, - ratification.after_digest, - ), - _ => format!( - "Ratified {} clause(s): {}\nDigest {} → {}\nThey are injected from the next turn; the prompt-cache prefix moved with them.", - ratification.accepted_clause_ids.len(), - ratification.accepted_clause_ids.join(", "), - ratification.before_digest, - ratification.after_digest, - ), + let Some(reviewed) = reviewed else { + let text = match locale { + Locale::ZhHans => { + "未批准任何条款:请先用 /constitution suggestions 审阅待批准条款。".to_string() + } + _ => "Nothing was ratified: review the pending clauses with /constitution suggestions first.".to_string(), + }; + return (text, None); + }; + match constitution.ratify(reviewed, ids, None) { + Err(err) => ( + match locale { + Locale::ZhHans => format!("未批准任何条款:{err}"), + _ => format!("Nothing was ratified: {err}"), }, + None, + ), + Ok(ratification) => match ratification.constitution.save_to(&path) { + Err(err) => ( + match locale { + Locale::ZhHans => format!("批准已计算但保存失败,文件未更改:{err:#}"), + _ => format!( + "Ratification was computed but could not be saved; the file is unchanged: {err:#}" + ), + }, + None, + ), + Ok(()) => ( + match locale { + Locale::ZhHans => format!( + "已批准 {} 条:{}\n摘要 {} → {}\n这些条款从下一轮起作为会话记录中的消息发送给模型;提示词缓存前缀不变。", + ratification.accepted_clause_ids.len(), + ratification.accepted_clause_ids.join(", "), + ratification.before_digest, + ratification.after_digest, + ), + _ => format!( + "Ratified {} clause(s): {}\nDigest {} → {}\nThey reach the model from the next turn as a message recorded in the session; the prompt-cache prefix is unchanged.", + ratification.accepted_clause_ids.len(), + ratification.accepted_clause_ids.join(", "), + ratification.before_digest, + ratification.after_digest, + ), + }, + Some(ratification.after_digest.clone()), + ), }, } } @@ -303,9 +333,9 @@ fn migrate_text(locale: Locale) -> String { receipt.before_digest, receipt.after_digest, if receipt.is_cache_stable() { - "未改变,提示词缓存保持有效" + "未改变,模型下一轮收到相同内容" } else { - "已改变,提示词缓存前缀随之变化" + "已改变,下一轮作为新的会话消息发送" }, ), _ => format!( @@ -315,9 +345,9 @@ fn migrate_text(locale: Locale) -> String { receipt.before_digest, receipt.after_digest, if receipt.is_cache_stable() { - "unchanged, so the prompt cache survives" + "unchanged, so the model receives the same text" } else { - "changed, so the prompt-cache prefix moved" + "changed; the new text is sent as a session message at the next turn" }, ), } @@ -545,7 +575,7 @@ fn preview_text(locale: Locale) -> String { let state = load_setup_state(); let load = load_user_constitution(); match load { - UserConstitutionStatus::Loaded { path, constitution } => { + UserConstitutionStatus::Loaded { constitution, .. } => { let active = user_constitution_is_active(state.as_ref()); let mut text = String::new(); if !active { @@ -554,7 +584,7 @@ fn preview_text(locale: Locale) -> String { } text.push_str( &constitution - .render_block(Some(&path)) + .render_block(None) .unwrap_or_else(|| structured_empty_text(locale).to_string()), ); text @@ -825,24 +855,24 @@ fn ignored_whale_warnings(warnings: &[String]) -> Vec<&str> { fn help_text(locale: Locale) -> String { match locale { Locale::ZhHans => "\ -用法:/constitution [status|preview|bundled|edit|review|repair|repo|explain|posture|help] +用法:/constitution [status|preview|base|suggestions|ratify |migrate|rollback|bundled|edit|review|repair|repo|explain|posture|help] 常用命令: -- /constitution:打开协作准则管理器和当前层级。 -- /constitution preview:显示会注入模型的确切用户全局协作准则块;缺失、空、无效或不可读时显示修复说明。 -- /constitution edit:打开 /setup 的引导式协作准则步骤;用 1-6 调整,按 G 预览,再按 G 保存。 +- /constitution:打开宪章管理器和当前层级。 +- /constitution preview:显示会注入模型的确切用户全局宪章块;缺失、空、无效或不可读时显示修复说明。 +- /constitution edit:打开 /setup 的引导式宪章步骤;用 1-6 调整,按 G 预览,再按 G 保存。 - /constitution repair:说明当前文件状态,然后打开同一个引导式修复步骤。 - /constitution bundled:记录使用内置/默认准则,不创建自定义文件。 - /constitution repo:查看 .codewhale/constitution.json 仓库本地准则。 -- /constitution explain:解释内置基础准则、用户全局协作准则、仓库协作准则、AGENTS.md、记忆和交接的区别。 +- /constitution explain:解释内置基础准则、用户全局宪章、仓库宪章、AGENTS.md、记忆和交接的区别。 - /constitution base:显示下一轮实际组装的确切基础提示词,附来源、摘要和字节/词元度量;只读,不发送请求,也不展开工具目录。 - /constitution suggestions:查看待批准的建议条款;它们不会注入模型,也不影响提示词缓存。 - /constitution ratify :明确批准某条建议条款;若基线在审阅后发生变化则拒绝批准。 -- /constitution migrate:把协作准则文件迁移到当前架构版本并给出回执;被拒绝时文件保持原样。 +- /constitution migrate:把宪章文件迁移到当前架构版本并给出回执;被拒绝时文件保持原样。 - /constitution rollback:恢复迁移前的备份。 -- /constitution posture:打开运行时姿态;协作准则只提供模型指导,不会更改批准、沙盒、Shell、网络、信任或 MCP 权限。", +- /constitution posture:打开运行时姿态;宪章只提供模型指导,不会更改批准、沙盒、Shell、网络、信任或 MCP 权限。", _ => "\ -Usage: /constitution [status|preview|bundled|edit|review|repair|repo|explain|posture|help] +Usage: /constitution [status|preview|base|suggestions|ratify |migrate|rollback|bundled|edit|review|repair|repo|explain|posture|help] Common commands: - /constitution: open the constitution manager and active stack. @@ -879,14 +909,14 @@ fn repair_text(locale: Locale) -> String { match locale { Locale::ZhHans => format!( "\ -用户全局协作准则修复 +用户全局宪章修复 当前文件:{file} 当前状态:{status} 记录选择:{choice} 有效性:{validity} -接下来将打开 /setup 的协作准则步骤。安全修复路径: +接下来将打开 /setup 的宪章步骤。安全修复路径: - 用 1-6 调整引导式草稿,按 G 预览,再按 G 保存新的结构化 constitution.json。 - 按 U 或运行 /constitution bundled 记录使用内置/默认准则;现有无效/空/不可读文件不会被注入。 - 用 /constitution preview 查看当前错误或渲染结果。 @@ -914,42 +944,42 @@ This only repairs the user-global constitution.json. Runtime approval, sandbox, fn manager_title(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "协作准则", + Locale::ZhHans => "宪章", _ => "Constitution", } } fn review_title(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "协作准则检查", + Locale::ZhHans => "宪章检查", _ => "Constitution Review", } } fn rendered_title(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "渲染后的用户协作准则", + Locale::ZhHans => "渲染后的用户宪章", _ => "Rendered User Constitution", } } fn repo_title(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "仓库本地协作准则", + Locale::ZhHans => "仓库本地宪章", _ => "Repo-Local Constitution", } } fn explanation_title(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "AGENTS.md 与协作准则", + Locale::ZhHans => "AGENTS.md 与宪章", _ => "AGENTS.md vs Constitution", } } fn no_repo_law_text(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "此工作区未找到仓库本地协作准则 .codewhale/constitution.json。", + Locale::ZhHans => "此工作区未找到仓库本地宪章 .codewhale/constitution.json。", _ => "No repo-local constitution found at .codewhale/constitution.json for this workspace.", } } @@ -963,7 +993,7 @@ fn inactive_preview_text(locale: Locale) -> &'static str { fn structured_empty_text(locale: Locale) -> &'static str { match locale { - Locale::ZhHans => "结构化协作准则为空。", + Locale::ZhHans => "结构化宪章为空。", _ => "The structured constitution is empty.", } } @@ -971,7 +1001,7 @@ fn structured_empty_text(locale: Locale) -> &'static str { fn missing_preview_text(locale: Locale, path: &std::path::Path) -> String { match locale { Locale::ZhHans => format!( - "未在 {} 找到结构化用户全局协作准则。\n\n当前使用内置准则。使用 /constitution edit 创建引导式长期偏好,或使用 /constitution bundled 明确记录内置/默认。", + "未在 {} 找到结构化用户全局宪章。\n\n当前使用内置准则。使用 /constitution edit 创建引导式长期偏好,或使用 /constitution bundled 明确记录内置/默认。", path.display() ), _ => format!( @@ -984,7 +1014,7 @@ fn missing_preview_text(locale: Locale, path: &std::path::Path) -> String { fn empty_preview_text(locale: Locale, path: &std::path::Path) -> String { match locale { Locale::ZhHans => format!( - "{} 的结构化用户全局协作准则为空。使用 /constitution repair 返回引导式协作准则步骤。", + "{} 的结构化用户全局宪章为空。使用 /constitution repair 返回引导式宪章步骤。", path.display() ), _ => format!( @@ -997,7 +1027,7 @@ fn empty_preview_text(locale: Locale, path: &std::path::Path) -> String { fn invalid_preview_text(locale: Locale, path: &std::path::Path, error: &str) -> String { match locale { Locale::ZhHans => format!( - "{} 的结构化用户全局协作准则无效,且不会注入。\n\n{error}\n\n使用 /constitution repair 返回引导式协作准则步骤。", + "{} 的结构化用户全局宪章无效,且不会注入。\n\n{error}\n\n使用 /constitution repair 返回引导式宪章步骤。", path.display() ), _ => format!( @@ -1010,7 +1040,7 @@ fn invalid_preview_text(locale: Locale, path: &std::path::Path, error: &str) -> fn unreadable_preview_text(locale: Locale, path: &std::path::Path, error: &str) -> String { match locale { Locale::ZhHans => format!( - "无法读取 {} 的结构化用户全局协作准则,且不会注入。\n\n{error}\n\n使用 /constitution repair 返回引导式协作准则步骤。", + "无法读取 {} 的结构化用户全局宪章,且不会注入。\n\n{error}\n\n使用 /constitution repair 返回引导式宪章步骤。", path.display() ), _ => format!( @@ -1022,7 +1052,7 @@ fn unreadable_preview_text(locale: Locale, path: &std::path::Path, error: &str) fn path_error_preview_text(locale: Locale, error: &str) -> String { match locale { - Locale::ZhHans => format!("无法为用户全局协作准则解析 CODEWHALE_HOME:\n\n{error}"), + Locale::ZhHans => format!("无法为用户全局宪章解析 CODEWHALE_HOME:\n\n{error}"), _ => { format!("Could not resolve CODEWHALE_HOME for the user-global constitution:\n\n{error}") } @@ -1033,19 +1063,19 @@ fn agents_explanation(locale: Locale) -> &'static str { match locale { Locale::ZhHans => { "\ -AGENTS.md 与协作准则 +AGENTS.md 与宪章 内置基础准则是精简的全局判断约定:身份、事实、验证、克制和优先级顺序。 -用户全局协作准则是个人长期偏好。它是结构化数据,确定性渲染,并低于当前用户请求和内置基础准则。 +用户全局宪章是个人长期偏好。它是结构化数据,确定性渲染,并低于当前用户请求和内置基础准则。 -.codewhale/constitution.json 是仓库本地协作准则。它属于某个工作区,并作为独立的仓库协作准则块渲染。 +.codewhale/constitution.json 是仓库本地宪章。它属于某个工作区,并作为独立的仓库宪章块渲染。 AGENTS.md 和项目说明是项目规则/实现指导。它们可以描述构建命令、仓库规范和本地流程;按优先级顺序,它们低于当前用户请求和内置基础准则,高于用户全局长期偏好、记忆和交接。 WHALE.md 已忽略。将普通项目说明迁移到 AGENTS.md,将 Codewhale 专属权限策略迁移到 .codewhale/constitution.json。 -运行时姿态是独立设置。协作准则可以建议主动性,但不会改变批准策略、沙盒、Shell、网络、信任、MCP 权限或默认模式。使用 /constitution posture 查看这些控制。" +运行时姿态是独立设置。宪章可以建议主动性,但不会改变批准策略、沙盒、Shell、网络、信任、MCP 权限或默认模式。使用 /constitution posture 查看这些控制。" } _ => { "\ @@ -1106,17 +1136,17 @@ impl ConstitutionManagerCopy { fn for_locale(locale: Locale) -> Self { match locale { Locale::ZhHans => Self { - manager_header: "协作准则管理器", + manager_header: "宪章管理器", active_stack_header: "生效层级", bundled_active: "内置基础准则:始终生效", - user_global_label: "用户全局协作准则", - repo_local_label: "仓库本地协作准则", + user_global_label: "用户全局宪章", + repo_local_label: "仓库本地宪章", agents_label: "AGENTS/项目说明", legacy_whale_label: "旧版 WHALE.md", memory_handoff_label: "记忆/交接", memory_label: "记忆", handoff_label: "交接", - user_global_header: "用户全局协作准则", + user_global_header: "用户全局宪章", choice_label: "选择", source_label: "来源", file_label: "文件", @@ -1130,8 +1160,8 @@ impl ConstitutionManagerCopy { repo_action: "/constitution repo 会在存在时显示 .codewhale/constitution.json 本地准则。", maintenance_header: "维护", maintenance_actions: &[ - "编辑引导式协作准则:/constitution edit", - "预览渲染后的协作准则:/constitution preview", + "编辑引导式宪章:/constitution edit", + "预览渲染后的宪章:/constitution preview", "查看下一轮的确切基础提示词:/constitution base", "审阅待批准的建议条款:/constitution suggestions", "批准某条建议条款:/constitution ratify ", @@ -1140,7 +1170,7 @@ impl ConstitutionManagerCopy { "查看现有内容:/constitution review", "修复无效/空/不可读文件:/constitution repair", "显示仓库本地准则:/constitution repo", - "解释 AGENTS.md 与协作准则:/constitution explain", + "解释 AGENTS.md 与宪章:/constitution explain", "打开运行时姿态:/constitution posture", ], present: "存在", @@ -1205,7 +1235,7 @@ impl ConstitutionManagerCopy { } fn location_count_unit(&self, count: usize) -> &'static str { - if self.manager_header == "协作准则管理器" { + if self.manager_header == "宪章管理器" { "处" } else if count == 1 { "location" @@ -1215,7 +1245,7 @@ impl ConstitutionManagerCopy { } fn completed_for(&self, version: &str) -> String { - if self.manager_header == "协作准则管理器" { + if self.manager_header == "宪章管理器" { format!("当前(自 {version} 引入)") } else { format!("current (introduced in {version})") @@ -1446,6 +1476,14 @@ mod tests { .expect("usage message"); assert!(bare.contains("Usage: /constitution ratify ")); + let unreviewed = ConstitutionCmd::execute(&mut app, Some("ratify c1")) + .message + .expect("refusal message"); + assert!(unreviewed.contains("Nothing was ratified"), "{unreviewed}"); + + ConstitutionCmd::execute(&mut app, Some("suggestions")); + pop_pager_body(&mut app); + let unknown = ConstitutionCmd::execute(&mut app, Some("ratify nope")) .message .expect("refusal message"); @@ -1484,7 +1522,7 @@ mod tests { "{message}" ); assert!( - message.contains("the prompt cache survives"), + message.contains("the model receives the same text"), "a v1 file carries no clauses, so no model-facing byte moved: {message}" ); @@ -1550,9 +1588,9 @@ mod tests { assert!(result.message.is_none()); let body = pop_pager_body(&mut app); - assert!(body.contains("协作准则管理器")); + assert!(body.contains("宪章管理器")); assert!(body.contains("生效层级")); - assert!(body.contains("用户全局协作准则")); + assert!(body.contains("用户全局宪章")); assert!(body.contains("/constitution preview 会")); assert!(!body.contains("宪法")); assert!(!body.contains("Constitution Manager")); @@ -1588,7 +1626,7 @@ mod tests { assert!(result.message.is_none()); let body = pop_pager_body(&mut app); - assert!(body.contains("AGENTS.md 与协作准则")); + assert!(body.contains("AGENTS.md 与宪章")); assert!(body.contains(".codewhale/constitution.json")); assert!(body.contains("运行时姿态是独立设置")); assert!(!body.contains("宪法")); diff --git a/crates/tui/src/commands/groups/core/core.rs b/crates/tui/src/commands/groups/core/core.rs index e7c862ef70..1751e24e77 100644 --- a/crates/tui/src/commands/groups/core/core.rs +++ b/crates/tui/src/commands/groups/core/core.rs @@ -9,7 +9,7 @@ use crate::config::{ }; #[cfg(test)] use crate::reasoning_preference::ReasoningEffort; -use crate::tui::app::{App, AppAction}; +use crate::tui::app::{App, AppAction, AppModeUi}; use crate::tui::views::{HelpView, ModalKind, SubAgentsView, subagent_view_agents}; use codewhale_config::AppMode; use codewhale_localization::{Locale, MessageId, tr}; @@ -658,7 +658,7 @@ pub fn home_dashboard(app: &mut App) -> CommandResult { stats, "{} {}", tr(locale, MessageId::HomeMode), - app.mode.label() + app.mode.display_name_localized(locale) ); let _ = writeln!( stats, diff --git a/crates/tui/src/commands/groups/utility/jobs.rs b/crates/tui/src/commands/groups/utility/jobs.rs index 50ed97c07e..c2d5c21651 100644 --- a/crates/tui/src/commands/groups/utility/jobs.rs +++ b/crates/tui/src/commands/groups/utility/jobs.rs @@ -42,18 +42,11 @@ fn jobs(args: Option<&str>) -> CommandResult { match action.as_str() { "list" => CommandResult::action(AppAction::ShellJob(ShellJobAction::List)), - "show" | "inspect" => match id { + "show" | "inspect" | "poll" | "wait" => match id { Some(id) => CommandResult::action(AppAction::ShellJob(ShellJobAction::Show { id: id.to_string(), })), - None => CommandResult::error("Usage: /jobs show "), - }, - "poll" | "wait" => match id { - Some(id) => CommandResult::action(AppAction::ShellJob(ShellJobAction::Poll { - id: id.to_string(), - wait: action == "wait", - })), - None => CommandResult::error("Usage: /jobs poll "), + None => CommandResult::error(format!("Usage: /jobs {action} ")), }, "stdin" | "send" => match id { Some(id) if !rest.is_empty() => { diff --git a/crates/tui/src/commands/mod.rs b/crates/tui/src/commands/mod.rs index 345dc3bdfb..ff220b8c89 100644 --- a/crates/tui/src/commands/mod.rs +++ b/crates/tui/src/commands/mod.rs @@ -1111,8 +1111,8 @@ mod tests { // Consistency: group-iterated command count must match registry. // FEAT-015 registers one test-only contextual command (`/feat015ctx`) - // under `#[cfg(test)]` to prove the dual-path seam (D6); the nine - // production groups remain exactly 96 commands. + // under `#[cfg(test)]` to prove the dual-path seam (D6); it is not + // part of any production group. let test_only_count = command_infos() .iter() .filter(|info| info.name == "feat015ctx") diff --git a/crates/tui/src/commands/traits.rs b/crates/tui/src/commands/traits.rs index 96cfaa87ea..dd66b3849f 100644 --- a/crates/tui/src/commands/traits.rs +++ b/crates/tui/src/commands/traits.rs @@ -216,7 +216,7 @@ fn leading_literal_token(alternative: &str) -> Option<&str> { .unwrap_or(alternative.len()); let token = &alternative[..end]; // A word only counts when it is spelled the way a typed verb is spelled: - // starting lowercase (or a digit, for `/mode [act|plan|1|2|3]`) and made + // starting lowercase (or a digit, for `/mode [work|plan|1|2|3]`) and made // of ASCII word characters. `N`, `entry_id`, `--force` and // `path/to/export.json` are all values, not verbs. let mut chars = token.chars(); diff --git a/crates/tui/src/compaction.rs b/crates/tui/src/compaction.rs index 29d2f36f4c..3adce23231 100644 --- a/crates/tui/src/compaction.rs +++ b/crates/tui/src/compaction.rs @@ -572,9 +572,9 @@ pub(crate) fn estimate_tokens_for_message(message: &Message, include_thinking: b // assistant messages and across later user turns. ContentBlock::Thinking { thinking, .. } if include_thinking => thinking.len() / 4, ContentBlock::Thinking { .. } => 0, - ContentBlock::ToolUse { input, .. } => serde_json::to_string(input) - .map(|s| s.len() / 4) - .unwrap_or(100), + ContentBlock::ToolUse { input, .. } => { + compact_json_len(input).map_or(100, |len| len / 4) + } ContentBlock::ToolResult { content, content_blocks, @@ -596,15 +596,23 @@ pub(crate) fn estimate_tokens_for_message(message: &Message, include_thinking: b // tiles are typically ~1k tokens); erring high compacts slightly // early rather than overflowing. ContentBlock::ImageUrl { .. } => IMAGE_TOKEN_ESTIMATE, - ContentBlock::ServerToolUse { input, .. } => input.to_string().len() / 4, + ContentBlock::ServerToolUse { input, .. } => { + compact_json_len(input).unwrap_or_default() / 4 + } ContentBlock::ToolSearchToolResult { content, .. } | ContentBlock::CodeExecutionToolResult { content, .. } => { - content.to_string().len() / 4 + compact_json_len(content).unwrap_or_default() / 4 } }) .sum::() } +fn compact_json_len(value: &serde_json::Value) -> Option { + let mut counter = crate::utils::CountingWriter::new(); + serde_json::to_writer(&mut counter, value).ok()?; + Some(counter.count()) +} + /// Conservative flat token estimate for an inline image (`ContentBlock::ImageUrl`). /// Vision models bill images by resized tile count; ~1k tokens is a safe /// mid-range estimate that keeps the compaction trigger from under-reading an @@ -753,8 +761,7 @@ pub fn compaction_pressure_reached_with_billed( // Billing alone proving pressure short-circuits the walk (#perf-r5): // `estimated.max(billed) >= threshold` is unconditionally true when // `billed >= threshold`, so estimating cannot change the answer and the - // O(transcript) pass is skipped. Over-pressure sessions pay this check - // multiple times per step (pressure gate + decision re-check). + // O(transcript) pass is skipped. if billed >= config.token_threshold { return true; } diff --git a/crates/tui/src/core/authority/auto_review.rs b/crates/tui/src/core/authority/auto_review.rs index 1ec98fef85..49fd28d06c 100644 --- a/crates/tui/src/core/authority/auto_review.rs +++ b/crates/tui/src/core/authority/auto_review.rs @@ -1578,11 +1578,12 @@ fn shell_params_are_destructive_like(params: &Value, workspace: Option<&std::pat }) } -/// The non-bypassable floor must hold genuinely catastrophic writes even when -/// `command_safety` (tuned to avoid over-blocking build/test chains) rates -/// them merely `RequiresApproval`: `dd`/`shred`/`wipefs` onto a device, -/// `mkfs`, and a forced recursive delete of an absolute path that is not -/// provably inside a safe workspace (#3883 follow-up). +/// The background/headless floor, which Full Access skips, must hold +/// genuinely catastrophic writes even when `command_safety` (tuned to avoid +/// over-blocking build/test chains) rates them merely `RequiresApproval`: +/// `dd`/`shred`/`wipefs` onto a device, `mkfs`, and a forced recursive delete +/// of an absolute path that is not provably inside a safe workspace (#3883 +/// follow-up). fn argv_is_destroyer(argv: &[String], workspace: Option<&std::path::Path>) -> bool { let Some((command, args)) = argv.split_first() else { return false; diff --git a/crates/tui/src/core/engine.rs b/crates/tui/src/core/engine.rs index 9812f43973..7bcad4f191 100644 --- a/crates/tui/src/core/engine.rs +++ b/crates/tui/src/core/engine.rs @@ -4340,15 +4340,15 @@ impl Engine { } } - fn record_goal_usage_for_turn(&self, usage: &Usage, elapsed: std::time::Duration) { + fn record_goal_usage_for_turn(&self, usage: &Usage, started: Instant) { let token_delta = u64::from(usage.input_tokens).saturating_add(u64::from(usage.output_tokens)); - let time_delta_seconds = elapsed.as_secs(); + let time_delta_seconds = started.elapsed().as_secs(); if token_delta == 0 && time_delta_seconds == 0 { return; } match self.config.goal_state.lock() { - Ok(mut state) => state.record_usage(token_delta, time_delta_seconds), + Ok(mut state) => state.record_usage(token_delta, time_delta_seconds, started), Err(err) => tracing::warn!("goal state lock poisoned while recording usage: {err}"), } } @@ -6715,7 +6715,7 @@ impl Engine { // Update session usage self.session.total_usage.add(&turn.usage); if !self.is_acp_turn() { - self.record_goal_usage_for_turn(&turn.usage, turn.elapsed()); + self.record_goal_usage_for_turn(&turn.usage, turn.started_at); } // Cancellation wins until the terminal settlement decision. `run_turn` @@ -7273,7 +7273,7 @@ impl Engine { route.model.clone(), self.session.workspace.clone(), self.session.system_prompt.clone(), - self.session.messages.clone().into(), + self.session.messages.snapshot(), )) .with_cancel_token(self.cancel_token.clone()) .with_origin_turn_id(self.turn_counter.to_string()); @@ -7329,7 +7329,7 @@ impl Engine { route.model.clone(), self.session.workspace.clone(), self.session.system_prompt.clone(), - self.session.messages.clone().into(), + self.session.messages.snapshot(), )) .with_cancel_token(self.cancel_token.clone()) .with_shell_policy(authority.shell_policy()) diff --git a/crates/tui/src/core/engine/compaction.rs b/crates/tui/src/core/engine/compaction.rs index f7390dfe27..eda542bf08 100644 --- a/crates/tui/src/core/engine/compaction.rs +++ b/crates/tui/src/core/engine/compaction.rs @@ -358,7 +358,7 @@ impl Engine { ) => Some(result), }; self.session.total_usage.add(&compaction_usage); - self.record_goal_usage_for_turn(&compaction_usage, started.elapsed()); + self.record_goal_usage_for_turn(&compaction_usage, started); self.emit_compaction_usage(&compaction_usage, started.elapsed()) .await; @@ -524,12 +524,12 @@ impl Engine { self.session.latest_parent_input_tokens, ); let prepared = if !*auto_compaction_suppressed - && crate::compaction::compaction_pressure_reached_with_billed( - &self.session.messages, - self.session.system_prompt.as_ref(), - &auto_compaction_config, - billed_input_tokens, - ) { + && auto_compaction_config.enabled + && billed_input_tokens + .and_then(|tokens| usize::try_from(tokens).ok()) + .unwrap_or(0) + >= auto_compaction_config.token_threshold + { let mut prepared = self.prepare_compaction_envelope(auto_compaction_config); prepared.tools = active_tools.map(<[Tool]>::to_vec); Some(prepared) diff --git a/crates/tui/src/core/engine/context.rs b/crates/tui/src/core/engine/context.rs index a78608e0bf..68b9230fc1 100644 --- a/crates/tui/src/core/engine/context.rs +++ b/crates/tui/src/core/engine/context.rs @@ -543,10 +543,41 @@ fn compact_structured_tool_result_for_context( // content actually parses as a gate result, so non-gate `tasks` // results fall through to the generic path unchanged. "task_gate_run" | "tasks" => compact_task_gate_run_result_for_context(raw), - _ => None, + _ => compact_todo_write_result_for_context(raw, metadata), } } +fn compact_todo_write_result_for_context( + raw: &str, + metadata: Option<&Value>, +) -> Option { + let metadata = metadata?; + if metadata.get("canonical_tool").and_then(Value::as_str) != Some("todo_write") { + return None; + } + let header = raw + .lines() + .next() + .filter(|line| line.starts_with("Todo list updated ("))?; + let active = metadata + .pointer("/task_updates/checklist/items")? + .as_array()? + .iter() + .find(|item| item.get("status").and_then(Value::as_str) == Some("in_progress")); + let text = match active { + Some(item) => format!( + "{header}\nIn progress: #{} {}", + item.get("id").and_then(Value::as_u64).unwrap_or_default(), + item.get("content") + .and_then(Value::as_str) + .unwrap_or_default() + .trim(), + ), + None => format!("{header}\nNo item in progress"), + }; + Some(ContextSummary { text, lossy: false }) +} + #[cfg(test)] pub(crate) fn compact_tool_result_for_context( model: &str, diff --git a/crates/tui/src/core/engine/preview/tests.rs b/crates/tui/src/core/engine/preview/tests.rs index 2a75830e86..6739f9c00b 100644 --- a/crates/tui/src/core/engine/preview/tests.rs +++ b/crates/tui/src/core/engine/preview/tests.rs @@ -1091,7 +1091,7 @@ async fn exhausted_active_goal_remains_previewable() { .goal_state .lock() .expect("goal state") - .record_usage(100, 0); + .record_usage(100, 0, std::time::Instant::now()); let prompt = "continue the release"; let planned = plan(&config, &identity, false, prompt).await; @@ -1117,7 +1117,7 @@ async fn resumed_goal_with_raised_budget_becomes_previewable_again() { ); { let mut state = engine.config.goal_state.lock().expect("goal state"); - state.record_usage(100, 0); + state.record_usage(100, 0, std::time::Instant::now()); state .mark_paused(GoalPauseReason::BudgetLimit) .expect("pause goal"); @@ -1154,7 +1154,7 @@ async fn lowering_active_goal_budget_below_used_tokens_keeps_preview_open() { .goal_state .lock() .expect("goal state") - .record_usage(100, 0); + .record_usage(100, 0, std::time::Instant::now()); sync_goal_state_from_host( &engine.config.goal_state, Some("finish the release"), diff --git a/crates/tui/src/core/engine/tests/test_cases_04.rs b/crates/tui/src/core/engine/tests/test_cases_04.rs index 2a96519cfc..180cccc759 100644 --- a/crates/tui/src/core/engine/tests/test_cases_04.rs +++ b/crates/tui/src/core/engine/tests/test_cases_04.rs @@ -561,7 +561,7 @@ async fn exhausted_goal_reaches_route_failure_without_budget_pause() { }; let (mut engine, handle) = Engine::new(engine_config, &config); let goal_state = engine.config.goal_state.clone(); - goal_state.lock().expect("goal lock").record_usage(11, 0); + goal_state.lock().expect("goal lock").record_usage(11, 0, std::time::Instant::now()); let invalid_route_config = without_named_custom_route(config); engine.authoritative_route_config = @@ -776,7 +776,7 @@ async fn cross_turn_goal_continuation_stops_at_an_enforced_token_budget() { .goal_state .lock() .expect("goal lock") - .record_usage(100, 0); + .record_usage(100, 0, std::time::Instant::now()); let action = engine.goal_continuation_if_active(); if enforce { assert!( diff --git a/crates/tui/src/core/engine/tests/test_cases_13.rs b/crates/tui/src/core/engine/tests/test_cases_13.rs index 41166fc8c4..3e86456eb4 100644 --- a/crates/tui/src/core/engine/tests/test_cases_13.rs +++ b/crates/tui/src/core/engine/tests/test_cases_13.rs @@ -471,8 +471,8 @@ fn messages_with_turn_metadata_returns_stored_session_messages() { // === To-do state reaches the model through its own tool results === // // Codewhale has one To-do list. The model learns what is on it the way it -// learns anything else: from the result its own `work_update` call returned, -// which is ordinary persisted history. No request re-states the list, on any +// learns anything else: from its own `work_update` call and the short receipt +// it returned, which are ordinary persisted history. No request re-states the list, on any // step. The complete list stays visible in the UI, which is a different // surface from the request. diff --git a/crates/tui/src/core/engine/tests/test_cases_15.rs b/crates/tui/src/core/engine/tests/test_cases_15.rs index 4907a2d08d..ec5a9792c7 100644 --- a/crates/tui/src/core/engine/tests/test_cases_15.rs +++ b/crates/tui/src/core/engine/tests/test_cases_15.rs @@ -435,7 +435,7 @@ fn turn_metadata_surfaces_goal_budget_only_while_goal_active() { let mut goal = engine.config.goal_state.lock().expect("goal lock"); goal.create("Finish telemetry visibility".to_string(), Some(2_000)) .expect("create goal"); - goal.record_usage(1_000, 100); + goal.record_usage(1_000, 100, std::time::Instant::now()); } let user_msg = engine diff --git a/crates/tui/src/core/engine/turn_loop.rs b/crates/tui/src/core/engine/turn_loop.rs index e45c70ac29..295a0f2240 100644 --- a/crates/tui/src/core/engine/turn_loop.rs +++ b/crates/tui/src/core/engine/turn_loop.rs @@ -2161,8 +2161,7 @@ impl Engine { !child.authority.runtime.has_foreground_ownership() }) { // A detached child's caller remains background even - // for a synchronous tool. Full Access cannot bypass - // the existing catastrophic-background safety floor. + // for a synchronous tool. RunOrigin::Background } else { auto_review_run_origin_for_plan(detached_start) @@ -8254,7 +8253,12 @@ mod tests { async fn goal_continuation_publishes_current_usage_without_accruing_twice() { let tmp = tempdir().expect("tempdir"); let (engine, handle) = goal_continuation_cadence_engine(&tmp, 0, true); - engine.config.goal_state.lock().unwrap().record_usage(5, 0); + engine + .config + .goal_state + .lock() + .unwrap() + .record_usage(5, 0, std::time::Instant::now()); let registry = goal_continuation_registry(&engine); let mut count = 0; let usage = Usage { diff --git a/crates/tui/src/core/engine/turn_loop/model_step.rs b/crates/tui/src/core/engine/turn_loop/model_step.rs index 8e64cf7305..5e6642446b 100644 --- a/crates/tui/src/core/engine/turn_loop/model_step.rs +++ b/crates/tui/src/core/engine/turn_loop/model_step.rs @@ -315,6 +315,9 @@ impl Engine { } } progress.turn_error = Some(display_message); + if envelope.severity == crate::error_taxonomy::ErrorSeverity::Warning { + envelope.severity = crate::error_taxonomy::ErrorSeverity::Error; + } let _ = self.send_event(Event::error(envelope)).await; return PhaseResult::Return(( TurnOutcomeStatus::Failed, diff --git a/crates/tui/src/core/turn.rs b/crates/tui/src/core/turn.rs index 8c096b6e52..7fe841db54 100644 --- a/crates/tui/src/core/turn.rs +++ b/crates/tui/src/core/turn.rs @@ -18,7 +18,7 @@ use crate::core::events::TurnRoute; use crate::snapshot::{SnapshotRepo, TakenSnapshot}; use codewhale_models::Usage; use std::path::Path; -use std::time::{Duration, Instant}; +use std::time::Instant; /// Which configured limit governs a turn's step budget (#5994). #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -186,11 +186,6 @@ impl TurnContext { self.step } - /// Get the elapsed time - pub fn elapsed(&self) -> Duration { - self.started_at.elapsed() - } - /// Complete the existing request projection with observed turn-exit facts. /// A turn that never prepared a request has no request snapshot to publish. pub(crate) fn terminal_request_snapshot( diff --git a/crates/tui/src/fleet/executor.rs b/crates/tui/src/fleet/executor.rs index b9eed4d9d1..f521446376 100644 --- a/crates/tui/src/fleet/executor.rs +++ b/crates/tui/src/fleet/executor.rs @@ -1698,46 +1698,6 @@ mod tests { assert!(!cmd.args.join(" ").contains("--max-tool-calls")); } - #[test] - fn default_max_turns_does_not_add_a_hidden_worker_cap() { - use clap::Parser; - - let exec = FleetExecConfig::default(); - let workspace = TempDir::new().unwrap(); - for requested_steps in [None, Some(0), Some(13)] { - let mut task = task("x"); - task.budget = requested_steps.map(|max_steps| FleetTaskBudget { - max_steps: Some(max_steps), - ..FleetTaskBudget::default() - }); - let spec = launch_spec(&task, workspace.path()); - let cmd = build_worker_exec_command_with_launch_spec( - "codewhale", - &task, - &spec, - &exec, - None, - &[], - ) - .expect("production worker command"); - let cli = crate::Cli::try_parse_from( - std::iter::once("codewhale").chain(cmd.args.iter().map(String::as_str)), - ) - .expect("production worker args must parse"); - let Some(crate::Commands::Exec(args)) = cli.command else { - panic!("expected worker exec command"); - }; - let expected = requested_steps.filter(|steps| *steps > 0); - assert_eq!(args.max_turns, expected); - assert_eq!(args.max_tool_calls, None); - // Follow omission beyond argv through the real CLI resolver. This - // previously installed 200 despite correct unbounded launch args. - let turn = crate::core::turn::TurnContext::new(crate::exec_max_steps(args.max_turns)); - assert_eq!(turn.step_limit(), expected); - assert_eq!(turn.stop_diagnostics.effective_max_steps, expected); - } - } - #[test] fn stream_line_maps_tool_use_to_running_tool() { let line = r#"{"type":"tool_use","name":"read_file","id":"call-7","input":{}}"#; diff --git a/crates/tui/src/lib/terminal_mode_test_cases_03.rs b/crates/tui/src/lib/terminal_mode_test_cases_03.rs index e984ba602c..61685c0c0c 100644 --- a/crates/tui/src/lib/terminal_mode_test_cases_03.rs +++ b/crates/tui/src/lib/terminal_mode_test_cases_03.rs @@ -1363,3 +1363,72 @@ } } } + + #[test] + fn default_max_turns_does_not_add_a_hidden_worker_cap() { + use crate::fleet::executor::build_worker_exec_command_with_launch_spec; + use crate::fleet::worker_runtime::fleet_task_to_worker_spec_with_profiles; + use codewhale_config::FleetExecConfig; + use codewhale_protocol::fleet::{FleetHostSpec, FleetTaskSpec, FleetWorkerSpec}; + + let exec = FleetExecConfig::default(); + let workspace = tempfile::TempDir::new().unwrap(); + let worker = FleetWorkerSpec { + id: "worker-1".to_string(), + name: "Worker 1".to_string(), + host: FleetHostSpec::Local, + trust_level: None, + labels: std::collections::BTreeMap::new(), + capabilities: Vec::new(), + max_concurrent_tasks: Some(1), + }; + for requested_steps in [None, Some(0), Some(13)] { + let mut task = serde_json::json!({ + "id": "t1", + "name": "Smoke", + "objective": "prove it runs", + "instructions": "x", + "worker": { "role": "reviewer", "tool_profile": "read-only" } + }); + if let Some(max_steps) = requested_steps { + task["budget"] = serde_json::json!({ "max_steps": max_steps }); + } + let task: FleetTaskSpec = serde_json::from_value(task).unwrap(); + let spec = fleet_task_to_worker_spec_with_profiles( + "worker-1", + "run-1", + &task, + &worker, + "auto", + workspace.path(), + workspace.path(), + &[], + None, + ) + .unwrap(); + let cmd = build_worker_exec_command_with_launch_spec( + "codewhale", + &task, + &spec, + &exec, + None, + &[], + ) + .expect("production worker command"); + let cli = Cli::try_parse_from( + std::iter::once("codewhale").chain(cmd.args.iter().map(String::as_str)), + ) + .expect("production worker args must parse"); + let Some(Commands::Exec(args)) = cli.command else { + panic!("expected worker exec command"); + }; + let expected = requested_steps.filter(|steps| *steps > 0); + assert_eq!(args.max_turns, expected); + assert_eq!(args.max_tool_calls, None); + // Follow omission beyond argv through the real CLI resolver. This + // previously installed 200 despite correct unbounded launch args. + let turn = crate::core::turn::TurnContext::new(exec_max_steps(args.max_turns)); + assert_eq!(turn.step_limit(), expected); + assert_eq!(turn.stop_diagnostics.effective_max_steps, expected); + } + } diff --git a/crates/tui/src/oauth.rs b/crates/tui/src/oauth.rs index a0975a6963..d4588ba8f7 100644 --- a/crates/tui/src/oauth.rs +++ b/crates/tui/src/oauth.rs @@ -282,9 +282,6 @@ pub struct OAuthProviderParams<'a> { /// account instead of reusing the browser's session. Sent unless /// [`OAuthEnvOverrides::no_account_prompt_var`] is set. pub account_choice_extras: &'a [(&'a str, &'a str)], - /// Honest client identity for issuers that require one (ChatGPT's - /// `originator`). Never impersonate another CLI. - pub originator: Option<&'a str>, /// Remote revoke path under the issuer, pinned rather than discovered: /// revoke must still clear local credentials when the issuer is /// unreachable, so a discovery fetch would only add a failure mode to a @@ -325,7 +322,6 @@ pub const XAI_OAUTH_PARAMS: OAuthProviderParams<'static> = OAuthProviderParams { device_poll_floor_secs: 30, authorize_extras: &[], account_choice_extras: &[], - originator: None, revoke_path: None, callback_path: "", loopback_ports: &[], @@ -353,7 +349,6 @@ pub const CLAUDE_OAUTH_PARAMS: OAuthProviderParams<'static> = OAuthProviderParam device_poll_floor_secs: 0, authorize_extras: &[], account_choice_extras: &[], - originator: None, revoke_path: None, callback_path: "/oauth/code/callback", loopback_ports: &[], @@ -368,7 +363,6 @@ pub const CHATGPT_OAUTH_PARAMS: OAuthProviderParams<'static> = OAuthProviderPara default_issuer: CHATGPT_OAUTH_ISSUER, default_client_id: CHATGPT_OAUTH_CLIENT_ID, default_scopes: CHATGPT_OAUTH_SCOPE, - originator: None, env: OAuthEnvOverrides { issuer_vars: &["CODEWHALE_CHATGPT_OAUTH_ISSUER"], client_id_vars: &["CODEWHALE_CHATGPT_OAUTH_CLIENT_ID"], @@ -461,7 +455,6 @@ pub const ORCAROUTER_OAUTH_PARAMS: OAuthProviderParams<'static> = OAuthProviderP device_poll_floor_secs: 30, authorize_extras: &[], account_choice_extras: &[], - originator: None, revoke_path: None, callback_path: "/callback", // OrcaRouter validates `callback_url` per request and accepts any @@ -1854,9 +1847,6 @@ pub fn build_authorize_url( .append_pair("code_challenge", &pkce.challenge) .append_pair("code_challenge_method", "S256") .append_pair("state", state); - if let Some(originator) = params.originator { - url.query_pairs_mut().append_pair("originator", originator); - } for (key, value) in params.authorize_extras { url.query_pairs_mut().append_pair(key, value); } @@ -3182,9 +3172,7 @@ fn apply_token_response( entry.oidc_issuer = Some(issuer.to_string()); entry.oidc_client_id = Some(client_id.to_string()); entry.auth_mode = Some("oidc".to_string()); - entry.originator = oauth_provider_params(provider) - .originator - .map(ToOwned::to_owned); + entry.originator = None; if let Some(id_token) = token.id_token.clone() { if provider != OAuthProvider::Chatgpt && let Some(account_id) = account_id_from_id_token(&id_token) @@ -4528,7 +4516,6 @@ impl PluginOAuthConfig { device_poll_floor_secs: 0, authorize_extras: &[], account_choice_extras: &[], - originator: None, revoke_path: None, callback_path: &self.callback_path, loopback_ports: &[], diff --git a/crates/tui/src/provider_readiness.rs b/crates/tui/src/provider_readiness.rs index 7f2b38d6a0..5dc414113a 100644 --- a/crates/tui/src/provider_readiness.rs +++ b/crates/tui/src/provider_readiness.rs @@ -457,7 +457,7 @@ impl ResolvedProviderReadiness { Self::LocalUnchecked => Cow::Borrowed("local · not checked"), Self::Ready => Cow::Borrowed("ready"), Self::ConnectionCheckedModelUnchecked => { - Cow::Borrowed("models endpoint 2xx · model not checked") + Cow::Borrowed("endpoint reachable · model not checked") } Self::SavedLastCheckFailed { category, .. } => { Cow::Owned(format!("last check failed ({category})")) @@ -1075,7 +1075,7 @@ mod tests { ); assert_eq!( ResolvedProviderReadiness::ConnectionCheckedModelUnchecked.label(), - "models endpoint 2xx · model not checked" + "endpoint reachable · model not checked" ); assert!(!ResolvedProviderReadiness::ConnectionCheckedModelUnchecked.can_attempt()); } diff --git a/crates/tui/src/remote_control.rs b/crates/tui/src/remote_control.rs index 40221fec6a..2e2b32b7b8 100644 --- a/crates/tui/src/remote_control.rs +++ b/crates/tui/src/remote_control.rs @@ -784,7 +784,7 @@ pub struct PendingRemoteApproval { } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -enum Status { +pub(crate) enum Status { #[default] Off, Connecting, @@ -1631,6 +1631,11 @@ impl RemoteControlController { } } + #[must_use] + pub(crate) fn status(&self) -> Status { + self.status + } + /// Test-only: advertise a validated live session link without a control /// plane. Mirrors the shape the runner-lease parser installs (`Connected` /// plus validated links) so `/rc link`/`/rc open` routing can be exercised diff --git a/crates/tui/src/rlm/session.rs b/crates/tui/src/rlm/session.rs index 220fbeb8fd..1b14e3cb01 100644 --- a/crates/tui/src/rlm/session.rs +++ b/crates/tui/src/rlm/session.rs @@ -127,7 +127,7 @@ pub struct SessionObjectSnapshot { pub model: String, pub workspace: PathBuf, pub system_prompt: Option, - pub messages: Vec, + pub messages: Arc>, } impl SessionObjectSnapshot { @@ -137,14 +137,14 @@ impl SessionObjectSnapshot { model: String, workspace: PathBuf, system_prompt: Option, - messages: Vec, + messages: impl Into>>, ) -> Self { Self { session_id, model, workspace, system_prompt, - messages, + messages: messages.into(), } } diff --git a/crates/tui/src/runtime_handoff.rs b/crates/tui/src/runtime_handoff.rs index 822d83dd29..ea26ea960b 100644 --- a/crates/tui/src/runtime_handoff.rs +++ b/crates/tui/src/runtime_handoff.rs @@ -583,7 +583,7 @@ pub(crate) fn shell_completion_runtime_message( let payload = events .iter() .map(|event| { - serde_json::json!({ + let mut entry = serde_json::json!({ "task_id": event.task_id, "command": event.command, "status": format!("{:?}", event.status), @@ -599,8 +599,15 @@ pub(crate) fn shell_completion_runtime_message( "owner_agent_name": event.owner_agent_name, "origin_tool_call_id": event.origin_tool_call_id, "origin_turn_id": event.origin_turn_id, - }) - .to_string() + }); + if event.status == crate::tools::shell::ShellStatus::Killed { + entry["kill_note"] = + serde_json::json!(crate::tools::shell_output::kill_outcome_note(&format!( + "{}{}", + event.stdout_tail, event.stderr_tail + ))); + } + entry.to_string() }) .collect::>() .join("\n"); diff --git a/crates/tui/src/runtime_threads.rs b/crates/tui/src/runtime_threads.rs index 52f8832793..8a2f7dda92 100644 --- a/crates/tui/src/runtime_threads.rs +++ b/crates/tui/src/runtime_threads.rs @@ -3135,10 +3135,11 @@ impl RuntimeThreadStore { /// Publish many items at once, paying the items directory's costs once. /// - /// Each `save_item` sweeps the whole items directory for stale temp files - /// and fsyncs it — right for one record, ruinous for the hundreds a fork - /// clones (measured: 22 ms of directory scan per item, 34 s for one fork's - /// 771). The per-record checks and the atomic replace are unchanged; see + /// Each `save_item` fsyncs the items directory — right for one record, + /// ruinous for the hundreds a fork clones. The stale-temp sweep is + /// throttled per directory inside `write_atomic`; unthrottled it cost 22 ms + /// of directory scan per item, 34 s for one fork's 771. The per-record + /// checks and the atomic replace are unchanged; see /// [`crate::utils::write_atomic_batch`]. /// /// Ordering stays the caller's: items, then their turns, then the thread @@ -10602,12 +10603,30 @@ impl RuntimeThreadManager { until: Option>, group_by: UsageGroupBy, ) -> Result { + let store = self.store.clone(); + let (threads, turns_by_thread) = tokio::task::spawn_blocking(move || { + let threads = store.list_threads()?; + let mut turns_by_thread: HashMap> = HashMap::new(); + if let Some(first) = threads.first() { + validated_record_id(&first.id, "thread id")?; + for turn in store.list_all_turns()? { + turns_by_thread + .entry(turn.thread_id.clone()) + .or_default() + .push(turn); + } + } + Ok::<_, anyhow::Error>((threads, turns_by_thread)) + }) + .await + .context("Runtime usage aggregation task failed")??; + let mut buckets: std::collections::BTreeMap = std::collections::BTreeMap::new(); let mut totals = UsageTotals::default(); - for thread in self.store.list_threads()? { - let turns = self.store.list_turns_for_thread(&thread.id)?; - for turn in turns { + for thread in &threads { + validated_record_id(&thread.id, "thread id")?; + for turn in turns_by_thread.get(&thread.id).into_iter().flatten() { let parent_route = turn.effective_route_envelope(); let parent_dispatched_at = parent_route .as_ref() @@ -10621,8 +10640,8 @@ impl RuntimeThreadManager { group_by, parent_route.as_ref(), usage, - &turn, - &thread, + turn, + thread, ); } for receipt in &turn.decision_receipts { @@ -10649,8 +10668,8 @@ impl RuntimeThreadManager { &mut buckets, group_by, child, - &turn, - &thread, + turn, + thread, ); } } @@ -10662,8 +10681,8 @@ impl RuntimeThreadManager { group_by, &drop_record.route, drop_record.reason, - &turn, - &thread, + turn, + thread, ); } } @@ -10677,8 +10696,8 @@ impl RuntimeThreadManager { &mut buckets, group_by, turn.routed_usage_dropped_records, - &turn, - &thread, + turn, + thread, ); } } @@ -12968,10 +12987,9 @@ impl RuntimeThreadManager { let mut saved_turn_ids = Vec::new(); let mut saved_item_ids = Vec::new(); let persistence = (|| -> Result<()> { - // Every cloned item in one batch. Each `save_item` sweeps the - // whole items directory and fsyncs it, which is right for a single - // record and ruinous for the hundreds a fork clones — the sweep - // gives the same answer every time. Items first, turns next, the + // Every cloned item in one batch. Each `save_item` fsyncs the items + // directory, which is right for a single record and ruinous for + // the hundreds a fork clones. Items first, turns next, the // thread record that makes them reachable last: the commit point is // unchanged, and the ids are recorded before the batch so a partial // write is still cleaned up. diff --git a/crates/tui/src/session_manager.rs b/crates/tui/src/session_manager.rs index 449e8bc80d..a613eae541 100644 --- a/crates/tui/src/session_manager.rs +++ b/crates/tui/src/session_manager.rs @@ -3678,11 +3678,15 @@ impl SessionManager { Ok(self .list_session_records()? .into_iter() - .map(|(_, metadata)| metadata) + .map(|(_, mut metadata)| { + self.apply_late_usage_to_metadata(&mut metadata); + metadata + }) .collect()) } - /// [`Self::list_sessions`], keeping the file each record was read from. + /// [`Self::list_sessions`] without the late-usage cost overlay, keeping + /// the file each record was read from. /// A record's file is not always `.json`: early builds wrote /// `session_.json`, and retention must address those by path. fn list_session_records(&self) -> std::io::Result> { @@ -3693,9 +3697,8 @@ impl SessionManager { let path = entry.path(); if path.extension().is_some_and(|ext| ext == "json") - && let Ok(mut session) = Self::load_session_metadata(&path) + && let Ok(session) = Self::load_session_metadata(&path) { - self.apply_late_usage_to_metadata(&mut session); sessions.push((path, session)); } } diff --git a/crates/tui/src/snapshot/repo.rs b/crates/tui/src/snapshot/repo.rs index 7da7284fc6..5e75423e18 100644 --- a/crates/tui/src/snapshot/repo.rs +++ b/crates/tui/src/snapshot/repo.rs @@ -964,7 +964,7 @@ impl SnapshotRepo { let checkout = run_git( &self.git_dir, &self.work_tree, - &["checkout", "--end-of-options", id.as_str(), "--", ":/"], + &["checkout", id.as_str(), "--", ":/"], )?; if !checkout.status.success() { return Err(io_other(format!( @@ -1363,7 +1363,6 @@ impl SnapshotRepo { let mut args: Vec = vec![ "--literal-pathspecs".to_string(), "checkout".to_string(), - "--end-of-options".to_string(), source.as_str().to_string(), "--".to_string(), ]; diff --git a/crates/tui/src/todo_snapshot.rs b/crates/tui/src/todo_snapshot.rs index 4e4259565b..97d7ecb745 100644 --- a/crates/tui/src/todo_snapshot.rs +++ b/crates/tui/src/todo_snapshot.rs @@ -1,11 +1,12 @@ //! Bounded renderings of a To-do snapshot. //! //! Codewhale has exactly one To-do list. The model learns what is on it the -//! same way it learns anything else: from the tool result its own `todo_write` -//! / `work_update` call returned, which is ordinary persisted transcript -//! state. **Nothing in this module is appended to a provider request**, and no -//! step of a tool loop re-states the list. If the model wants the current -//! list, it reads its own last tool result or calls the tool again. +//! same way it learns anything else: from its own `todo_write` / +//! `work_update` call, whose input is the whole list, confirmed by a short +//! receipt (counts and the item in progress). Both are ordinary persisted +//! transcript state. **Nothing in this module is appended to a provider +//! request**, and no step of a tool loop re-states the list. If the model +//! wants the current list, it reads its own last call or calls the tool again. //! //! What this module owns is the small set of places that render a snapshot //! *once*, at an explicit seam a person asked for: diff --git a/crates/tui/src/tools/goal.rs b/crates/tui/src/tools/goal.rs index 6fafdb6869..00222fd3a2 100644 --- a/crates/tui/src/tools/goal.rs +++ b/crates/tui/src/tools/goal.rs @@ -391,8 +391,11 @@ impl GoalState { } } - pub fn record_usage(&mut self, token_delta: u64, time_delta_seconds: u64) { - if self.is_active() { + pub fn record_usage(&mut self, token_delta: u64, time_delta_seconds: u64, since: Instant) { + if self.is_active() + || (self.objective.is_some() + && self.finished_at.is_some_and(|finished| finished >= since)) + { self.tokens_used = self.tokens_used.saturating_add(token_delta); self.time_used_seconds = self.time_used_seconds.saturating_add(time_delta_seconds); } @@ -1157,7 +1160,7 @@ impl ToolSpec for UpdateGoalTool { }, "progress": { "type": "object", - "description": "Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", + "description": "Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", "properties": { "percent": { "type": "integer", @@ -1208,9 +1211,9 @@ impl ToolSpec for UpdateGoalTool { } let status = required_str(&input, "status")?.trim().to_ascii_lowercase(); let progress = parse_progress_report(&input)?; - if progress.is_some() && !matches!(status.as_str(), "not_achieved" | "advisory") { + if progress.is_some() && !matches!(status.as_str(), "not_achieved" | "advisory" | "yield") { return Err(ToolError::invalid_input( - "progress is only accepted with status not_achieved or advisory", + "progress is only accepted with status not_achieved, advisory or yield", )); } let snapshot = { @@ -1269,6 +1272,9 @@ impl ToolSpec for UpdateGoalTool { } "yield" => { state.mark_yielded().map_err(ToolError::invalid_input)?; + if progress.is_some() { + state.progress = progress; + } } "advisory" => { let advisory = input @@ -1543,7 +1549,7 @@ mod tests { Some(1_200), status, ); - state.record_usage(300, 12); + state.record_usage(300, 12, std::time::Instant::now()); state.record_continuation(); let before = state.snapshot(); @@ -1569,7 +1575,7 @@ mod tests { blocked .create("resume the release goal".to_string(), Some(4_000)) .expect("create blocked fixture"); - blocked.record_usage(750, 44); + blocked.record_usage(750, 44, std::time::Instant::now()); blocked.record_continuation(); blocked .mark_blocked("provider failed".to_string()) @@ -1662,7 +1668,7 @@ mod tests { state .create("finish the first objective".to_string(), Some(1_200)) .expect("create first goal"); - state.record_usage(300, 12); + state.record_usage(300, 12, std::time::Instant::now()); state.record_continuation(); state .mark_complete( @@ -2110,7 +2116,7 @@ mod tests { ); { let mut goal = state.lock().expect("goal lock"); - goal.record_usage(300, 12); + goal.record_usage(300, 12, std::time::Instant::now()); goal.record_continuation(); } @@ -2339,7 +2345,7 @@ mod tests { .await .expect_err("progress is not terminal evidence"); assert!( - err.to_string().contains("not_achieved or advisory"), + err.to_string().contains("not_achieved, advisory or yield"), "{err}" ); diff --git a/crates/tui/src/tools/mod.rs b/crates/tui/src/tools/mod.rs index b7877b9e53..e276dbcd6c 100644 --- a/crates/tui/src/tools/mod.rs +++ b/crates/tui/src/tools/mod.rs @@ -68,7 +68,7 @@ pub mod search; pub mod send_later; pub mod session; pub mod shell; -mod shell_output; +pub(crate) mod shell_output; pub mod skill; pub mod spec; pub mod speech; diff --git a/crates/tui/src/tools/shell.rs b/crates/tui/src/tools/shell.rs index 6ea187260c..aef47ada03 100644 --- a/crates/tui/src/tools/shell.rs +++ b/crates/tui/src/tools/shell.rs @@ -1003,7 +1003,7 @@ fn shared_output_pipe() -> io::Result<(File, File, File)> { } const SYNC_READER_DRAIN_TIMEOUT: Duration = Duration::from_secs(5); -const STALE_NO_OUTPUT_AFTER: Duration = Duration::from_secs(60); +pub(crate) const QUIET_NO_OUTPUT_AFTER: Duration = Duration::from_secs(60); /// Grace between SIGTERM and SIGKILL on the shell kill path (timeout, /// cancel, drop). Bounded so a SIGTERM-ignoring command is force-killed @@ -1586,6 +1586,9 @@ impl BackgroundShell { /// Kill the process fn kill(&mut self) -> Result<()> { + if self.poll() && self.status != ShellStatus::Running { + return Ok(()); + } #[cfg(unix)] if self.ownership == ShellOwnership::PersistPending && let Some(process_group_id) = self.child.as_ref().and_then(ShellChild::process_id) @@ -1714,13 +1717,6 @@ impl BackgroundShell { .unwrap_or((0, String::new())); let elapsed_since_output_ms = (self.status == ShellStatus::Running) .then(|| u64::try_from(self.last_output_at.elapsed().as_millis()).unwrap_or(u64::MAX)); - // A live PTY can wait indefinitely for input. Silence does not mean it - // lost its process owner; marking it stale hides its transport from API - // clients and incorrectly prevents reconnect/resize after one minute. - let stale = self.terminal_size.is_none() - && elapsed_since_output_ms.is_some_and(|elapsed| { - elapsed >= u64::try_from(STALE_NO_OUTPUT_AFTER.as_millis()).unwrap_or(u64::MAX) - }); ShellJobSnapshot { id: self.id.clone(), job_id: self.id.clone(), @@ -1736,7 +1732,7 @@ impl BackgroundShell { stdout_len, stderr_len, stdin_available: self.stdin.is_some() && self.status == ShellStatus::Running, - stale, + stale: false, elapsed_since_output_ms, linked_task_id: self.linked_task_id.clone(), owner_agent_id: self @@ -3124,20 +3120,7 @@ impl ShellManager { .processes .get_mut(task_id) .ok_or_else(|| anyhow!("Task {task_id} not found"))?; - - if wait && shell.status == ShellStatus::Running { - let timeout = Duration::from_millis(timeout_ms.clamp(1000, 600_000)); - let deadline = Instant::now() + timeout; - - while shell.status == ShellStatus::Running && Instant::now() < deadline { - if shell.poll() { - break; - } - std::thread::sleep(Duration::from_millis(100)); - } - } else { - shell.poll(); - } + wait_while_running(shell, wait, timeout_ms); let ( stdout_delta, @@ -3196,6 +3179,20 @@ impl ShellManager { Some(u64::try_from(shell.last_output_at.elapsed().as_millis()).unwrap_or(u64::MAX)) } + pub fn running_progress(&mut self, task_id: &str) -> Option { + let shell = self.processes.get_mut(task_id)?; + shell.poll(); + if shell.status != ShellStatus::Running { + return None; + } + let job = shell.job_snapshot(); + let quiet_secs = shell.last_output_at.elapsed().as_secs(); + Some(format!( + "Progress: last output {quiet_secs}s ago; {}.", + output_phase_hint(&format!("{}\n{}", job.stdout_tail, job.stderr_tail)) + )) + } + /// Kill a running background process pub fn kill(&mut self, task_id: &str) -> Result { let shell = self @@ -3207,6 +3204,17 @@ impl ShellManager { shell.snapshot() } + fn mark_cancel_reported(&mut self, result: &ShellResult) { + if result.status == ShellStatus::Killed + && let Some(shell) = result + .task_id + .as_deref() + .and_then(|id| self.processes.get_mut(id)) + { + shell.completion_reported = true; + } + } + pub fn kill_for_session( &mut self, active_session_id: &str, @@ -3239,18 +3247,20 @@ impl ShellManager { ) -> Result> { let ids = self .processes - .iter() + .iter_mut() .filter(|(_, shell)| { - shell.status == ShellStatus::Running - && !active_session_id.is_empty() - && shell.owner_session_id == active_session_id + !active_session_id.is_empty() && shell.owner_session_id == active_session_id + }) + .filter_map(|(id, shell)| { + shell.poll(); + (shell.status == ShellStatus::Running).then(|| id.clone()) }) - .map(|(id, _)| id.clone()) .collect::>(); let mut results = Vec::with_capacity(ids.len()); for id in ids { results.push(self.kill(&id)?); } + results.retain(|result| result.status == ShellStatus::Killed); Ok(results) } @@ -3345,17 +3355,6 @@ impl ShellManager { self.get_output_delta(task_id, wait, timeout_ms) } - pub fn poll_delta_for_session( - &mut self, - active_session_id: &str, - task_id: &str, - wait: bool, - timeout_ms: u64, - ) -> Result { - self.require_session_owner(task_id, active_session_id)?; - self.get_output_delta(task_id, wait, timeout_ms) - } - fn get_output_delta_for_session( &mut self, active_session_id: &str, @@ -3782,6 +3781,22 @@ impl ShellManager { } } +fn wait_while_running(shell: &mut BackgroundShell, wait: bool, timeout_ms: u64) { + if wait && shell.status == ShellStatus::Running { + let timeout = Duration::from_millis(timeout_ms.clamp(1000, 600_000)); + let deadline = Instant::now() + timeout; + + while shell.status == ShellStatus::Running && Instant::now() < deadline { + if shell.poll() { + break; + } + std::thread::sleep(Duration::from_millis(100)); + } + } else { + shell.poll(); + } +} + fn job_status_rank(status: &ShellStatus, stale: bool) -> u8 { if stale { return 4; @@ -6695,6 +6710,15 @@ impl BashTool { { object.insert("wait_timeout_ms".to_string(), json!(timeout_ms)); } + if matches!(status, ShellStatus::Running) + && let Some(progress) = context + .shell_manager + .lock() + .map_err(|_| ToolError::execution_failed("shell manager lock poisoned"))? + .running_progress(task_id) + { + result.content = format!("{progress}\n{}", result.content); + } if let Some(interruption) = interruption { let (action, key) = match interruption { ShellWaitInterruption::Canceled => ("canceled", "wait_canceled"), @@ -6823,10 +6847,24 @@ impl BashTool { .filter(|(_, status)| *status == ShellStatus::Running) .count(); let settled = statuses.len().saturating_sub(running_after); - let lines: Vec = statuses - .iter() - .map(|(id, status)| format!("{id}: {status:?}")) - .collect(); + let lines: Vec = { + let mut manager = context + .shell_manager + .lock() + .map_err(|_| ToolError::execution_failed("shell manager lock poisoned"))?; + statuses + .iter() + .map(|(id, status)| { + let progress = (*status == ShellStatus::Running) + .then(|| manager.running_progress(id)) + .flatten(); + match progress { + Some(progress) => format!("{id}: {status:?} ({progress})"), + None => format!("{id}: {status:?}"), + } + }) + .collect() + }; let still_running: Vec<&str> = statuses .iter() .filter(|(_, status)| *status == ShellStatus::Running) @@ -6993,6 +7031,9 @@ impl BashTool { let results = manager .kill_running_for_session(&context.state_namespace) .map_err(|err| ToolError::execution_failed(err.to_string()))?; + for result in &results { + manager.mark_cancel_reported(result); + } if results.is_empty() { return Ok(ToolResult { content: "No running background commands.".to_string(), @@ -7029,15 +7070,20 @@ impl BashTool { let result = manager .kill_for_session(&context.state_namespace, task_id) .map_err(|err| ToolError::execution_failed(err.to_string()))?; + manager.mark_cancel_reported(&result); let task_id = result .task_id .clone() .unwrap_or_else(|| task_id.to_string()); Ok(ToolResult { - content: format!( - "Canceled background command: {task_id}. {}", - kill_outcome_note(&format!("{}{}", result.stdout, result.stderr)) - ), + content: if result.status == ShellStatus::Killed { + format!( + "Canceled background command: {task_id}. {}", + kill_outcome_note(&format!("{}{}", result.stdout, result.stderr)) + ) + } else { + format!("{} Nothing was killed.", wait_timing_line(&result)) + }, success: true, metadata: Some(json!({ "status": format!("{:?}", result.status), diff --git a/crates/tui/src/tools/shell/tests.rs b/crates/tui/src/tools/shell/tests.rs index 57f51e176b..08f4d86bcc 100644 --- a/crates/tui/src/tools/shell/tests.rs +++ b/crates/tui/src/tools/shell/tests.rs @@ -2652,7 +2652,7 @@ fn test_job_list_poll_cancel_and_stale_snapshot() { } #[test] -fn running_job_snapshot_marks_no_output_stale_after_threshold() { +fn running_job_snapshot_keeps_silent_live_job_live() { let tmp = tempdir().expect("tempdir"); let mut manager = ShellManager::new(tmp.path().to_path_buf()); @@ -2662,7 +2662,7 @@ fn running_job_snapshot_marks_no_output_stale_after_threshold() { { let shell = manager.processes.get_mut(&task_id).expect("live shell"); - shell.last_output_at = Instant::now() - STALE_NO_OUTPUT_AFTER - Duration::from_millis(1); + shell.last_output_at = Instant::now() - QUIET_NO_OUTPUT_AFTER - Duration::from_millis(1); } let job = manager @@ -2672,10 +2672,10 @@ fn running_job_snapshot_marks_no_output_stale_after_threshold() { .expect("running job"); assert_eq!(job.status, ShellStatus::Running); - assert!(job.stale, "silent running job should be marked stale"); + assert!(!job.stale, "silence alone must not mark a live job stale"); assert!( job.elapsed_since_output_ms - .is_some_and(|elapsed| elapsed >= STALE_NO_OUTPUT_AFTER.as_millis() as u64), + .is_some_and(|elapsed| elapsed >= QUIET_NO_OUTPUT_AFTER.as_millis() as u64), "elapsed no-output time should be exposed: {job:?}" ); } @@ -5773,14 +5773,14 @@ fn pty_resize_updates_live_terminal_and_rejects_finished_or_pipe_jobs() { // Reopening a client after an idle minute must retain this live PTY's // identity and resize eligibility; output silence is normal at a prompt. manager.processes.get_mut(&id).unwrap().last_output_at = - Instant::now() - STALE_NO_OUTPUT_AFTER - Duration::from_millis(1); + Instant::now() - QUIET_NO_OUTPUT_AFTER - Duration::from_millis(1); let idle = manager.inspect_job(&id).unwrap().snapshot; assert_eq!(idle.status, ShellStatus::Running); assert!(idle.stdin_available); assert!(!idle.stale, "an idle live PTY must remain reconnectable"); assert!( idle.elapsed_since_output_ms - .is_some_and(|ms| ms >= STALE_NO_OUTPUT_AFTER.as_millis() as u64) + .is_some_and(|ms| ms >= QUIET_NO_OUTPUT_AFTER.as_millis() as u64) ); let size = PtyDimensions { rows: 37, diff --git a/crates/tui/src/tools/subagent/engine.rs b/crates/tui/src/tools/subagent/engine.rs index 3d1c7978f8..cd543a0c1f 100644 --- a/crates/tui/src/tools/subagent/engine.rs +++ b/crates/tui/src/tools/subagent/engine.rs @@ -1673,6 +1673,7 @@ pub(crate) async fn drive_child_actor( let mut input_open = true; let mut pending_input: Option = None; let mut cancellation_deadline = None; + let mut tool_names: HashMap = HashMap::new(); // The launch permit alone is not a started turn. Project only Core's // admitted lifecycle event, once across work, report and route retries. let mut started = false; @@ -1795,14 +1796,19 @@ pub(crate) async fn drive_child_actor( job.hard_deadline.map(Into::into), ).await; } + Event::ToolCallStarted { id, name, .. } => { + tool_names.insert(id.clone(), name.clone()); + } Event::ToolExecutionStarted { id } => { if let Some(mailbox) = runtime.mailbox.as_ref() { - let _ = mailbox.send(MailboxMessage::ToolCallStarted { agent_id: agent_id.clone(), tool_name: format!("Core tool {id}"), step: job.steps() }); + let tool_name = tool_names.get(id).cloned().unwrap_or_else(|| "tool".to_string()); + let _ = mailbox.send(MailboxMessage::ToolCallStarted { agent_id: agent_id.clone(), tool_name, step: job.steps() }); } } Event::ToolCallComplete { id, name, result, .. } => { + let label = tool_names.remove(id).unwrap_or_else(|| name.clone()); record_agent_progress(&runtime, &agent_id, AgentProgressEventMeta::new(AgentWorkerStatus::RunningTool).with_tool(name.clone()), - format!("Core tool {id} {}", if result.is_ok() { "settled" } else { "refused or failed" })); + format!("{label} {}", if result.is_ok() { "done" } else { "failed" })); } Event::Status { message, .. } => record_agent_progress(&runtime, &agent_id, AgentProgressEventMeta::new(AgentWorkerStatus::Running), message.clone()), diff --git a/crates/tui/src/tools/subagent/mod.rs b/crates/tui/src/tools/subagent/mod.rs index 81e66a3b4a..a0335d4ce1 100644 --- a/crates/tui/src/tools/subagent/mod.rs +++ b/crates/tui/src/tools/subagent/mod.rs @@ -10274,15 +10274,28 @@ impl SubAgentTranscriptArtifactWriter { }) } - fn sync_messages(&mut self, messages: &[Message], durable: bool) -> Result<()> { - if messages.len() < self.synced_live_messages { - return Err(anyhow!( + fn unsynced_messages<'a>(&self, messages: &'a [Message]) -> Result<&'a [Message]> { + messages.get(self.synced_live_messages..).ok_or_else(|| { + anyhow!( "sub-agent transcript history shrank from {} to {} messages", self.synced_live_messages, messages.len() - )); - } - self.append_messages(&messages[self.synced_live_messages..], durable)?; + ) + }) + } + + fn sync_messages(&mut self, messages: &[Message], durable: bool) -> Result<()> { + let unsynced = self.unsynced_messages(messages)?; + self.append_messages(unsynced, durable)?; + self.synced_live_messages = messages.len(); + Ok(()) + } + + fn sync_projected_messages(&mut self, messages: &[Message], durable: bool) -> Result<()> { + let unsynced = crate::image_attach::safe_tool_result_message_projection( + self.unsynced_messages(messages)?, + ); + self.append_messages(&unsynced, durable)?; self.synced_live_messages = messages.len(); Ok(()) } @@ -14415,11 +14428,8 @@ async fn insert_subagent_full_transcript_handle( // bounded message tail — embedding it verbatim would duplicate that tail // inside one payload. Keep checkpoint metadata, drop its messages, and // record how much of the true history the bounded tail omits. - let projected_messages = crate::image_attach::safe_tool_result_message_projection(messages); - let (bounded_messages, omitted_messages) = bounded_tail_messages( - &projected_messages, - SUBAGENT_TRANSCRIPT_MESSAGE_BUDGET_BYTES, - ); + let (bounded_messages, omitted_messages) = + bounded_tail_messages(messages, SUBAGENT_TRANSCRIPT_MESSAGE_BUDGET_BYTES); let checkpoint_meta = checkpoint.map(|checkpoint| SubAgentCheckpoint { omitted_messages: checkpoint.message_count, messages: Vec::new(), @@ -14427,7 +14437,7 @@ async fn insert_subagent_full_transcript_handle( }); let transcript_artifact = transcript_artifact.map(|writer| { let synced = - match writer.sync_messages(&projected_messages, *status != SubAgentStatus::Running) { + match writer.sync_projected_messages(messages, *status != SubAgentStatus::Running) { Ok(()) => true, Err(err) => { tracing::warn!( @@ -14439,7 +14449,7 @@ async fn insert_subagent_full_transcript_handle( false } }; - writer.metadata(synced && writer.synced_live_messages == projected_messages.len()) + writer.metadata(synced && writer.synced_live_messages == messages.len()) }); let payload = json!({ "kind": "subagent_full_transcript", @@ -14544,23 +14554,27 @@ fn bound_subagent_tool_result( /// budgets. Exact JSON size via serde; unserializable messages (should not /// happen) count as 1 KiB so they still consume budget. fn approximate_message_bytes(message: &Message) -> usize { - serde_json::to_string(message).map_or(1024, |s| s.len()) + let mut counter = crate::utils::CountingWriter::new(); + serde_json::to_writer(&mut counter, message).map_or(1024, |()| counter.count()) } -/// Keep the most recent messages whose combined approximate size fits -/// `budget_bytes`. Always keeps at least the final message (even if it alone -/// exceeds the budget) so a non-empty history stays continuable. Returns the -/// retained tail and how many older messages were omitted. +/// Keep the most recent messages, after `safe_tool_result_message_projection`, +/// whose combined approximate size fits `budget_bytes`. Always keeps at least +/// the final message (even if it alone exceeds the budget) so a non-empty +/// history stays continuable. Returns the retained tail and how many older +/// messages were omitted. fn bounded_tail_messages(messages: &[Message], budget_bytes: usize) -> (Vec, usize) { let mut kept_rev: Vec = Vec::new(); let mut used = 0usize; for message in messages.iter().rev() { - let size = approximate_message_bytes(message); + let projected = + crate::image_attach::safe_tool_result_message_projection(std::slice::from_ref(message)); + let size: usize = projected.iter().map(approximate_message_bytes).sum(); if !kept_rev.is_empty() && used.saturating_add(size) > budget_bytes { break; } used = used.saturating_add(size); - kept_rev.push(message.clone()); + kept_rev.extend(projected); } kept_rev.reverse(); let omitted = messages.len().saturating_sub(kept_rev.len()); @@ -14576,11 +14590,8 @@ fn build_subagent_checkpoint( ) -> SubAgentCheckpoint { let created_at_ms = epoch_millis_now(); let checkpoint_id = format!("{agent_id}:step:{steps_taken}:ts:{created_at_ms}"); - let projected_messages = crate::image_attach::safe_tool_result_message_projection(messages); - let (bounded_messages, omitted_messages) = bounded_tail_messages( - &projected_messages, - SUBAGENT_CHECKPOINT_MESSAGE_BUDGET_BYTES, - ); + let (bounded_messages, omitted_messages) = + bounded_tail_messages(messages, SUBAGENT_CHECKPOINT_MESSAGE_BUDGET_BYTES); SubAgentCheckpoint { checkpoint_id: checkpoint_id.clone(), agent_id: agent_id.to_string(), diff --git a/crates/tui/src/tui/active_cell.rs b/crates/tui/src/tui/active_cell.rs index 9c8f0a7610..efbbc34156 100644 --- a/crates/tui/src/tui/active_cell.rs +++ b/crates/tui/src/tui/active_cell.rs @@ -338,6 +338,7 @@ mod tests { entries: vec![ExploringEntry { label: label.to_string(), status: ToolStatus::Running, + error: None, }], })) } diff --git a/crates/tui/src/tui/app.rs b/crates/tui/src/tui/app.rs index 8b37404e84..641f31d10b 100644 --- a/crates/tui/src/tui/app.rs +++ b/crates/tui/src/tui/app.rs @@ -1961,6 +1961,7 @@ pub struct App { /// Exact evidence remains attached to each mutation receipt in all modes. pub inline_diff_mode: InlineDiffMode, pub ui_locale: Locale, + pub constitution_reviewed_digest: Option, pub cost_currency: CostCurrency, /// Route payment truth. Model pricing alone cannot distinguish metered /// API calls from OAuth or token-plan quota. @@ -3534,7 +3535,7 @@ impl App { #[must_use] pub fn mode_startup_default_receipt(&self, mode: AppMode) -> String { self.tr(MessageId::ModeAlreadyActiveSavedAsDefault) - .replace("{mode}", mode.display_name()) + .replace("{mode}", &mode.display_name_localized(self.ui_locale)) } /// Surface any startup-default write that failed since the last drain. @@ -3601,7 +3602,8 @@ impl App { Ok(()) }); self.push_status_toast( - "Legacy full-access mode is deprecated — use Act + Full Access (Shift+Tab)".to_string(), + "Legacy full-access mode is deprecated — use Work + Full Access (Shift+Tab)" + .to_string(), StatusToastLevel::Warning, Some(8_000), ); @@ -3968,7 +3970,7 @@ impl App { if self.mode == AppMode::Plan { self.push_status_toast( format!( - "Permissions set to {}. Plan stays Read Only; this applies in Act and Operate.", + "Permissions set to {}. Plan stays Read Only; this applies in Work and Operate.", next.permission_chip_label() ), StatusToastLevel::Info, @@ -5385,6 +5387,7 @@ impl App { /// exclusive `Arc` mutates in place, a shared one detaches first, so an /// outstanding engine snapshot can never observe the mutation. pub fn api_messages_mut(&mut self) -> &mut Vec { + self.context_token_cache.get_mut().clear(); Arc::make_mut(&mut self.api_messages) } @@ -5394,7 +5397,7 @@ impl App { pub fn push_api_message(&mut self, message: Message) { self.api_message_stamps .resize_with(self.api_messages.len(), Utc::now); - self.api_messages_mut().push(message); + Arc::make_mut(&mut self.api_messages).push(message); self.api_message_stamps.push(Utc::now()); } @@ -5404,18 +5407,19 @@ impl App { /// that are new or were rewritten (compaction) are stamped now, which /// lands within a turn-event of the real append. The shared snapshot is /// installed without copying. - pub fn set_api_messages(&mut self, messages: Arc>) { - let keep = self + pub fn set_api_messages(&mut self, messages: Arc>) -> usize { + let unchanged = self .api_messages .iter() .zip(messages.iter()) .take_while(|(old, new)| old == new) - .count() - .min(self.api_message_stamps.len()); - self.api_message_stamps.truncate(keep); + .count(); + self.api_message_stamps + .truncate(unchanged.min(self.api_message_stamps.len())); self.api_message_stamps .resize_with(messages.len(), Utc::now); self.api_messages = messages; + unchanged } /// Install a resumed conversation, reusing the persisted journal's @@ -5629,6 +5633,34 @@ impl App { /// Pick the detail target for the current viewport. The footer hint and /// Alt+V both resolve through this so they agree on the target. #[must_use] + pub(crate) fn transcript_owner_at_line( + &self, + line_index: usize, + ) -> Option { + let (rendered, _) = self + .viewport + .transcript_cache + .line_meta() + .get(line_index)? + .cell_line()?; + Some(TranscriptActionOwner { + cell_index: self.original_cell_index_for_rendered(rendered), + identity_epoch: self.transcript_identity_epoch, + }) + } + + pub(crate) fn selection_owner_cell(&self) -> Option { + let selection = &self.viewport.transcript_selection; + selection + .owner + .filter(|owner| { + selection.is_active() + && owner.identity_epoch == self.transcript_identity_epoch + && self.cell_at_virtual_index(owner.cell_index).is_some() + }) + .map(|owner| owner.cell_index) + } + pub fn detail_cell_index_for_viewport( &self, top: usize, @@ -5640,11 +5672,14 @@ impl App { .map(|(idx, _)| self.original_cell_index_for_rendered(idx)) }; let selected = self - .viewport - .transcript_selection - .ordered_endpoints() - .and_then(|(start, _)| line_meta.get(start.line_index)) - .and_then(original) + .selection_owner_cell() + .or_else(|| { + self.viewport + .transcript_selection + .ordered_endpoints() + .and_then(|(start, _)| line_meta.get(start.line_index)) + .and_then(original) + }) .filter(|&idx| self.cell_has_detail_target(idx)); let start = top.min(line_meta.len().saturating_sub(1)); let end = start.saturating_add(visible).min(line_meta.len()); @@ -5763,7 +5798,16 @@ impl App { } // A pre-insertion action still names the old virtual index. Reject // it until the renderer establishes the owner's new position. + let previous_epoch = self.transcript_identity_epoch; self.transcript_identity_epoch = self.transcript_identity_epoch.wrapping_add(1); + if let Some(owner) = self.viewport.transcript_selection.owner.as_mut() + && owner.identity_epoch == previous_epoch + { + if owner.cell_index >= boundary { + owner.cell_index = owner.cell_index.saturating_add(added); + } + owner.identity_epoch = self.transcript_identity_epoch; + } for index in self.tool_cells.values_mut() { if *index >= boundary { *index = index.saturating_add(added); @@ -7346,11 +7390,7 @@ impl App { return effective.display_label_for_provider(provider).to_string(); } let effective = effective.display_label_for_provider(provider); - if requested == ReasoningEffort::Auto { - format!("auto: {effective}") - } else { - format!("{}→{effective}", requested.short_label()) - } + format!("{}→{effective}", requested.short_label()) } EffectiveReasoningEffort::ThinkingEnabledGranularityUnavailable => format!( "{}→thinking enabled; granularity unavailable", diff --git a/crates/tui/src/tui/app/init.rs b/crates/tui/src/tui/app/init.rs index 556ff83d8c..39de31d10f 100644 --- a/crates/tui/src/tui/app/init.rs +++ b/crates/tui/src/tui/app/init.rs @@ -935,6 +935,7 @@ impl App { show_tool_details, inline_diff_mode, ui_locale, + constitution_reviewed_digest: None, cost_currency, billing_presentation: provider_identity.as_ref().map_or( crate::route_billing::BillingPresentation::Unknown, diff --git a/crates/tui/src/tui/app/tests.rs b/crates/tui/src/tui/app/tests.rs index 326c56c755..71aa61650e 100644 --- a/crates/tui/src/tui/app/tests.rs +++ b/crates/tui/src/tui/app/tests.rs @@ -396,7 +396,7 @@ fn reasoning_effort_display_label_keeps_codex_top_tiers_distinct() { app.reasoning_effort = ReasoningEffort::Auto; app.last_effective_reasoning_effort = Some(EffectiveReasoningEffort::Tier(ReasoningEffort::Max)); - assert_eq!(app.reasoning_effort_display_label(), "auto: max"); + assert_eq!(app.reasoning_effort_display_label(), "auto→max"); } #[test] @@ -4021,7 +4021,7 @@ fn plan_permission_cycle_moves_the_baseline_and_leaves_plan_read_only() { assert!( app.status_toasts .iter() - .any(|toast| toast.text.contains("applies in Act and Operate")), + .any(|toast| toast.text.contains("applies in Work and Operate")), "the receipt must say when the new posture starts applying" ); diff --git a/crates/tui/src/tui/app/types.rs b/crates/tui/src/tui/app/types.rs index 802a95b4b3..ba689d5d69 100644 --- a/crates/tui/src/tui/app/types.rs +++ b/crates/tui/src/tui/app/types.rs @@ -856,10 +856,6 @@ pub enum ShellJobAction { Show { id: String, }, - Poll { - id: String, - wait: bool, - }, SendStdin { id: String, input: String, diff --git a/crates/tui/src/tui/approval.rs b/crates/tui/src/tui/approval.rs index c15fd5b09e..32c5b36fdb 100644 --- a/crates/tui/src/tui/approval.rs +++ b/crates/tui/src/tui/approval.rs @@ -151,6 +151,7 @@ pub struct ApprovalDetail { /// Preformatted shell lines for commands that benefit from safe wrapping /// or a compact write-file preview. `value` remains the original command. pub shell_lines: Option>, + pub is_preview: bool, } impl ApprovalRequest { @@ -272,11 +273,11 @@ impl ApprovalRequest { pub fn description_for_locale(&self, locale: Locale) -> String { match locale { - Locale::ZhHans => localized_description_zh_hans(self.category), - _ if self.category == ToolCategory::Shell => { + Locale::En if self.category == ToolCategory::Shell => { "Review the command before it runs.".to_string() } - _ => self.description.clone(), + Locale::En => self.description.clone(), + _ => localized_description(self.category, locale), } } @@ -337,9 +338,10 @@ impl ApprovalRequest { if matches!(detail.label.as_str(), "File" | "Path" | "Dir") { detail.value = workspace_relative(&detail.value, &self.workspace); } - let is_preview = detail.label == "Preview"; detail.label = localize_detail_label(&detail.label, locale).to_string(); - if is_preview && let Some(lines) = detail.shell_lines.as_mut() { + if detail.is_preview + && let Some(lines) = detail.shell_lines.as_mut() + { for line in lines.iter_mut() { *line = localize_preview_shell_line(semantic_tool_name, line, locale) .to_string(); @@ -460,8 +462,7 @@ fn build_impact_summary(tool_name: &str, category: ToolCategory, params: &Value) impacts } -fn localized_description_zh_hans(category: ToolCategory) -> String { - let locale = Locale::ZhHans; +fn localized_description(category: ToolCategory, locale: Locale) -> String { match category { ToolCategory::Safe => tr(locale, MessageId::ApprovalDescSafe).to_string(), ToolCategory::FileWrite => tr(locale, MessageId::ApprovalDescFileWrite).to_string(), @@ -565,6 +566,7 @@ fn build_prominent_details( label, value, shell_lines: None, + is_preview: false, }) .collect(); match category { @@ -574,6 +576,7 @@ fn build_prominent_details( label: "Command".to_string(), shell_lines: Some(format_shell_command_for_approval(&command)), value: command, + is_preview: false, }); } if let Some(workdir) = param_preview(params, &["workdir", "cwd"], 96) { @@ -581,6 +584,7 @@ fn build_prominent_details( label: "Dir".to_string(), value: workdir, shell_lines: None, + is_preview: false, }); } } @@ -590,6 +594,7 @@ fn build_prominent_details( label: "File".to_string(), value: path, shell_lines: None, + is_preview: false, }); } if let Some(preview_lines) = file_write_preview_lines(tool_name, params) { @@ -597,6 +602,7 @@ fn build_prominent_details( label: "Preview".to_string(), value: preview_lines.join("\n"), shell_lines: Some(preview_lines), + is_preview: true, }); } } @@ -606,6 +612,7 @@ fn build_prominent_details( label: "Path".to_string(), value: path, shell_lines: None, + is_preview: false, }); } } @@ -617,6 +624,7 @@ fn build_prominent_details( label: "Target".to_string(), value: target, shell_lines: None, + is_preview: false, }); } } @@ -629,6 +637,7 @@ fn build_prominent_details( label: label.to_string(), value, shell_lines: None, + is_preview: false, }); } } @@ -638,6 +647,7 @@ fn build_prominent_details( label: "Action".to_string(), value: action, shell_lines: None, + is_preview: false, }); } if let Some(kind) = param_preview(params, &["type"], 40) { @@ -645,6 +655,7 @@ fn build_prominent_details( label: "Type".to_string(), value: kind, shell_lines: None, + is_preview: false, }); } if let Some(prompt) = param_preview(params, &["prompt", "task", "message"], 200) { @@ -652,6 +663,7 @@ fn build_prominent_details( label: "Prompt".to_string(), value: prompt, shell_lines: None, + is_preview: false, }); } } @@ -665,6 +677,7 @@ fn build_prominent_details( label: "Input".to_string(), value: input, shell_lines: None, + is_preview: false, }); } } diff --git a/crates/tui/src/tui/approval/elevation.rs b/crates/tui/src/tui/approval/elevation.rs index 79dc6a0bbc..c9b892aa28 100644 --- a/crates/tui/src/tui/approval/elevation.rs +++ b/crates/tui/src/tui/approval/elevation.rs @@ -50,7 +50,7 @@ impl ElevationOption { ElevationOption::FullAccess => { "Retry without sandbox limits; grants unrestricted filesystem and network access" } - ElevationOption::Abort => "Cancel this run", + ElevationOption::Abort => "Skip only this tool call", } } diff --git a/crates/tui/src/tui/approval/previews.rs b/crates/tui/src/tui/approval/previews.rs index 429de7b9e4..9f00efdb51 100644 --- a/crates/tui/src/tui/approval/previews.rs +++ b/crates/tui/src/tui/approval/previews.rs @@ -312,34 +312,32 @@ pub(super) fn param_text(params: &Value, keys: &[&str]) -> Option { } pub(super) fn localize_detail_label(label: &str, locale: Locale) -> Cow<'static, str> { - match locale { - Locale::ZhHans => match label { - "Command" => tr(locale, MessageId::ApprovalLabelCommand), - "Dir" => tr(locale, MessageId::ApprovalLabelDir), - "File" => tr(locale, MessageId::ApprovalLabelFile), - "Preview" => tr(locale, MessageId::ApprovalLabelPreview), - "proposed content" => tr(locale, MessageId::ApprovalLabelProposedContent), - "replace this" => tr(locale, MessageId::ApprovalLabelReplaceThis), - "with this" => tr(locale, MessageId::ApprovalLabelWithThis), - "replacement content" => tr(locale, MessageId::ApprovalLabelReplacementContent), - "Path" => tr(locale, MessageId::ApprovalLabelPath), - "Target" => tr(locale, MessageId::ApprovalLabelTarget), - "Input" => tr(locale, MessageId::ApprovalLabelInput), - "Action" => tr(locale, MessageId::ApprovalLabelAction), - "Type" => tr(locale, MessageId::ApprovalLabelType), - "Prompt" => tr(locale, MessageId::ApprovalLabelPrompt), - "Goal" => "目标".into(), - "Children" => "子任务".into(), - "Writes" => "写入".into(), - "Shell" => "Shell".into(), - "Network" => "网络".into(), - "Budget" => "预算".into(), - "Trust mode" => "信任模式".into(), - "Auto-approve" => "自动批准".into(), - "Mode" => "模式".into(), - "Workspace" => "工作区".into(), - _ => label.to_string().into(), - }, + match label { + "Command" => tr(locale, MessageId::ApprovalLabelCommand), + "Dir" => tr(locale, MessageId::ApprovalLabelDir), + "File" => tr(locale, MessageId::ApprovalLabelFile), + "Preview" => tr(locale, MessageId::ApprovalLabelPreview), + "proposed content" => tr(locale, MessageId::ApprovalLabelProposedContent), + "replace this" => tr(locale, MessageId::ApprovalLabelReplaceThis), + "with this" => tr(locale, MessageId::ApprovalLabelWithThis), + "replacement content" => tr(locale, MessageId::ApprovalLabelReplacementContent), + "Path" => tr(locale, MessageId::ApprovalLabelPath), + "Target" => tr(locale, MessageId::ApprovalLabelTarget), + "Input" => tr(locale, MessageId::ApprovalLabelInput), + "Action" => tr(locale, MessageId::ApprovalLabelAction), + "Type" => tr(locale, MessageId::ApprovalLabelType), + "Prompt" => tr(locale, MessageId::ApprovalLabelPrompt), + _ if locale != Locale::ZhHans => label.to_string().into(), + "Goal" => "目标".into(), + "Children" => "子任务".into(), + "Writes" => "写入".into(), + "Shell" => "Shell".into(), + "Network" => "网络".into(), + "Budget" => "预算".into(), + "Trust mode" => "信任模式".into(), + "Auto-approve" => "自动批准".into(), + "Mode" => "模式".into(), + "Workspace" => "工作区".into(), _ => label.to_string().into(), } } diff --git a/crates/tui/src/tui/approval/tests.rs b/crates/tui/src/tui/approval/tests.rs index 2c29d8a9fd..6c753d5df1 100644 --- a/crates/tui/src/tui/approval/tests.rs +++ b/crates/tui/src/tui/approval/tests.rs @@ -2577,10 +2577,13 @@ fn test_elevation_render_en_has_expected_strings() { let lines = render_elevation_lines(&view, 70, 22); let joined = compact_elevation_text(&lines); assert!( - joined.contains("SandboxDenied"), + joined.contains("SandboxElevationRequired"), "missing en title:\n{joined}" ); - assert!(joined.contains("Tool:"), "missing en tool label:\n{joined}"); + assert!( + !joined.contains("Tool:"), + "the command row already names the shell:\n{joined}" + ); assert!(joined.contains("Cmd:"), "missing en cmd label:\n{joined}"); assert!( joined.contains("Reason:"), @@ -2618,7 +2621,7 @@ fn elevation_always_paints_every_option_including_the_safe_exit() { ); } assert!( - joined.contains("SandboxDenied") || joined.contains("SandboxElevationRequired"), + joined.contains("SandboxElevationRequired"), "{w}x{h}: the card lost its title:\n{joined}" ); for key in ["↑/↓", "Enter", "Esc"] { @@ -2643,11 +2646,7 @@ fn test_elevation_render_zh_hans_localizes_copy() { let view = ElevationView::new(elevation_shell_request(), Locale::ZhHans); let lines = render_elevation_lines(&view, 70, 22); let joined = compact_elevation_text(&lines); - assert!(joined.contains("沙箱拒绝"), "missing zh title:\n{joined}"); - assert!( - joined.contains("工具:"), - "missing zh tool label:\n{joined}" - ); + assert!(joined.contains("沙箱提权"), "missing zh title:\n{joined}"); assert!(joined.contains("命令:"), "missing zh cmd label:\n{joined}"); assert!( joined.contains("原因:"), @@ -2658,7 +2657,7 @@ fn test_elevation_render_zh_hans_localizes_copy() { "missing zh impact header:\n{joined}" ); let en_artifacts = [ - "SandboxDenied", + "SandboxElevationRequired", "Tool:", "Cmd:", "Reason:", @@ -2683,13 +2682,9 @@ fn test_elevation_render_ja_has_translated_copy() { let lines = render_elevation_lines(&view, 70, 22); let joined = compact_elevation_text(&lines); assert!( - joined.contains("サンドボックス拒否"), + joined.contains("サンドボックス昇格"), "missing ja title:\n{joined}" ); - assert!( - joined.contains("ツール:"), - "missing ja tool label:\n{joined}" - ); assert!( joined.contains("コマンド:"), "missing ja cmd label:\n{joined}" @@ -2698,7 +2693,7 @@ fn test_elevation_render_ja_has_translated_copy() { joined.contains("理由:"), "missing ja reason label:\n{joined}" ); - for eng in &["SandboxDenied", "Tool:", "Cmd:", "Reason:"] as &[&str] { + for eng in &["SandboxElevationRequired", "Tool:", "Cmd:", "Reason:"] as &[&str] { assert!( !joined.contains(eng), "English leak '{eng}' in ja:\n{joined}" @@ -2712,13 +2707,9 @@ fn test_elevation_render_zh_hant_has_translated_copy() { let lines = render_elevation_lines(&view, 70, 22); let joined = compact_elevation_text(&lines); assert!( - joined.contains("沙箱拒絕"), + joined.contains("沙箱提權"), "missing zh-Hant title:\n{joined}" ); - assert!( - joined.contains("工具:"), - "missing zh-Hant tool label:\n{joined}" - ); assert!( joined.contains("指令:"), "missing zh-Hant cmd label:\n{joined}" @@ -2763,7 +2754,7 @@ fn test_elevation_option_descriptions() { .description() .contains("filesystem and network access") ); - assert!(ElevationOption::Abort.description().contains("Cancel")); + assert!(ElevationOption::Abort.description().contains("Skip")); } #[test] diff --git a/crates/tui/src/tui/footer_hints.rs b/crates/tui/src/tui/footer_hints.rs index 8f6df92888..181b1a703a 100644 --- a/crates/tui/src/tui/footer_hints.rs +++ b/crates/tui/src/tui/footer_hints.rs @@ -39,10 +39,11 @@ pub(crate) fn retired(uses: &BTreeMap, key: &str) -> bool { impl App { /// Record one use of the binding behind footer hint `key`. /// - /// Persistence is best-effort and never blocks the input path: once a - /// hint is retired on disk the transaction is abandoned without a write, - /// so each key costs at most [`USES_TO_RETIRE`] writes per install. A - /// read-only home still retires the hint for the running session. + /// Persistence is best-effort. Once the in-memory count (seeded from + /// settings at startup) retires the hint, a use touches no file at all; + /// before that each of at most [`USES_TO_RETIRE`] uses per key runs one + /// settings transaction on this thread. A read-only home still retires + /// the hint for the running session. pub(crate) fn note_footer_hint_used(&mut self, key: &str) { if cfg!(test) { // Tests never touch the settings file here, so only the @@ -52,6 +53,9 @@ impl App { *count = count.saturating_add(1); return; } + if retired(&self.footer_hint_uses, key) { + return; + } let owned = key.to_string(); let persisted = Settings::transact_opt(|settings| { let count = settings.footer_hint_uses.get(&owned).copied().unwrap_or(0); diff --git a/crates/tui/src/tui/history.rs b/crates/tui/src/tui/history.rs index 2847f7fe6c..11f5c97dc6 100644 --- a/crates/tui/src/tui/history.rs +++ b/crates/tui/src/tui/history.rs @@ -958,6 +958,7 @@ impl ToolCell { || matches!( self, ToolCell::Exec(_) + | ToolCell::Mcp(_) | ToolCell::PatchSummary(_) | ToolCell::Review(_) | ToolCell::PlanUpdate(_) @@ -1008,9 +1009,7 @@ impl ToolCell { ) -> Vec> { match self { ToolCell::Exec(cell) => cell.render_with_locale(width, low_motion, mode, locale), - ToolCell::Exploring(cell) => { - cell.lines_with_motion_and_locale(width, low_motion, locale) - } + ToolCell::Exploring(cell) => cell.render_with_locale(width, low_motion, mode, locale), ToolCell::PlanUpdate(cell) => cell.lines_with_motion(width, low_motion), ToolCell::PatchSummary(cell) => cell.render( width, @@ -1279,11 +1278,22 @@ impl ExploringCell { self.lines_with_motion_and_locale(width, low_motion, Locale::En) } + #[cfg(test)] pub fn lines_with_motion_and_locale( &self, width: u16, low_motion: bool, locale: Locale, + ) -> Vec> { + self.render_with_locale(width, low_motion, RenderMode::Live, locale) + } + + pub(super) fn render_with_locale( + &self, + width: u16, + low_motion: bool, + mode: RenderMode, + locale: Locale, ) -> Vec> { let mut lines = Vec::new(); let status = self.status(); @@ -1309,14 +1319,19 @@ impl ExploringCell { // incoherent `read done · Searching …` (#4145). Read/list or mixed // cards keep the neutral `read` verb the Workspace card has always used. let family = exploring_card_family(&self.entries); - lines.push(render_tool_header_with_family_and_summary( + let header = render_tool_header_with_family_and_summary( family, header_summary.as_deref(), header_state.as_ref(), status, None, low_motion, - )); + ); + let header_shows_label = !multi_entry + && header_summary + .as_deref() + .is_some_and(|label| header_shows_in_full(&header, label, usize::from(width))); + lines.push(header); // Dot-grid status strip — one glyph per entry, showing parallel // fanout at a glance: ●=done ◐=running ✕=failed. @@ -1347,16 +1362,26 @@ impl ExploringCell { Style::default().fg(tool_glyph_color(e.status, family)), ) })); - let counts = format!( - " {done} done, {running} running{}", - if failed > 0 { - format!(", {failed} failed") - } else { - String::new() - }, - ); + let counts = [ + (done, codewhale_localization::MessageId::WorkflowCountDone), + ( + running, + codewhale_localization::MessageId::WorkflowCountRunning, + ), + ( + failed, + codewhale_localization::MessageId::WorkflowCountFailed, + ), + ] + .into_iter() + .filter(|(count, _)| *count > 0) + .map(|(count, id)| { + codewhale_localization::tr(locale, id).replace("{count}", &count.to_string()) + }) + .collect::>() + .join(", "); dot_spans.push(Span::styled( - counts, + format!(" {counts}"), Style::default().fg(tool_glyph_color(status, family)), )); lines.push(Line::from(dot_spans)); @@ -1370,13 +1395,13 @@ impl ExploringCell { tool_value_style(), width, )); - } else { + } else if !header_shows_label { let prefix = match entry.status { ToolStatus::Running => "live", ToolStatus::Success => "done", ToolStatus::Hydrated => "loaded", ToolStatus::Warning => "issue", - ToolStatus::Failed => "issue", + ToolStatus::Failed => "failed", }; lines.extend(render_compact_kv( prefix, @@ -1385,6 +1410,26 @@ impl ExploringCell { width, )); } + if let Some(error) = entry.error.as_deref() { + if multi_entry { + if let Some(reason) = error.lines().map(str::trim).find(|line| !line.is_empty()) + { + lines.extend(render_card_detail_line( + None, + reason, + tool_value_style(), + width, + )); + } + } else { + lines.extend(render_tool_output_mode( + error, + width, + TOOL_FAILURE_PREVIEW_LINES, + mode, + )); + } + } } lines } @@ -1402,6 +1447,7 @@ impl ExploringCell { pub struct ExploringEntry { pub label: String, pub status: ToolStatus, + pub error: Option, } /// Calm outcome and exact evidence for a structured File mutation. @@ -1426,7 +1472,13 @@ impl PatchSummaryCell { let header_summary = self .receipt .as_ref() - .map(FileMutationReceipt::outcome_label) + .map(|receipt| { + if inline_diff_mode == crate::settings::InlineDiffMode::Off { + receipt.outcome_label() + } else { + receipt.semantic_summary() + } + }) .unwrap_or_else(|| self.path.clone()); lines.push(render_tool_header_with_summary( "File", @@ -1667,15 +1719,19 @@ impl ViewImageCell { /// Render the image view cell into lines. pub fn lines_with_motion(&self, width: u16, low_motion: bool) -> Vec> { let path = self.path.display().to_string(); - let mut lines = vec![render_tool_header_with_summary( + let header = render_tool_header_with_summary( "Image", Some(&path), "done", ToolStatus::Success, None, low_motion, - )]; - lines.extend(render_compact_kv("path", &path, tool_value_style(), width)); + ); + let header_shows_path = header_shows_in_full(&header, &path, usize::from(width)); + let mut lines = vec![header]; + if !header_shows_path { + lines.extend(render_compact_kv("path", &path, tool_value_style(), width)); + } lines } } @@ -1695,20 +1751,24 @@ impl WebSearchCell { /// Render the web search cell into lines. pub fn lines_with_motion(&self, width: u16, low_motion: bool) -> Vec> { let mut lines = Vec::new(); - lines.push(render_tool_header_with_summary( + let header = render_tool_header_with_summary( "Search", Some(&self.query), tool_status_label(self.status), self.status, None, low_motion, - )); - lines.extend(render_compact_kv( - "query", - &self.query, - tool_value_style(), - width, - )); + ); + let header_shows_query = header_shows_in_full(&header, &self.query, usize::from(width)); + lines.push(header); + if !header_shows_query { + lines.extend(render_compact_kv( + "query", + &self.query, + tool_value_style(), + width, + )); + } if let Some(source) = self.source.as_ref() { lines.extend(render_compact_kv( "source", @@ -1810,7 +1870,7 @@ impl GenericToolCell { // Issue #241: when the underlying tool is a checklist/todo update and // the output is parseable, render a purpose-built progress card // instead of dumping the JSON into the generic tool block. - if let Some(lines) = self.try_render_as_checklist(width, low_motion, mode) { + if let Some(lines) = self.try_render_as_checklist(width, low_motion, mode, locale) { return lines; } @@ -1898,15 +1958,21 @@ impl GenericToolCell { &self.name, self.input_summary.as_deref(), ); - lines.push(render_tool_header_with_family_and_summary( + let header = render_tool_header_with_family_and_summary( family, header_summary.as_deref(), &tool_receipt_label(family, self.status, self.output.as_deref(), locale), self.status, None, low_motion, - )); - if should_show_raw_tool_name(&self.name, family, mode) { + ); + let header_has_args = self.input_summary.as_deref().is_some_and(|args| { + header_repeats_args(&header, header_summary.as_deref(), args, usize::from(width)) + }); + lines.push(header); + if should_show_raw_tool_name(&self.name, family, mode) + && !crate::tui::widgets::tool_card::should_show_tool_name_in_header(&self.name, family) + { lines.extend(render_compact_kv( "name", &self.name, @@ -1934,8 +2000,9 @@ impl GenericToolCell { )); } } else { - let show_args = matches!(self.status, ToolStatus::Running | ToolStatus::Failed) - || self.output.is_none(); + let show_args = (matches!(self.status, ToolStatus::Running | ToolStatus::Failed) + || self.output.is_none()) + && !header_has_args; if show_args && let Some(summary) = self.input_summary.as_ref() { lines.extend(render_compact_kv( "args", @@ -2002,6 +2069,7 @@ impl GenericToolCell { width: u16, low_motion: bool, mode: RenderMode, + locale: Locale, ) -> Option>> { if !is_checklist_tool_name(&self.name) { return None; @@ -2026,6 +2094,7 @@ impl GenericToolCell { &change, width, low_motion, + locale, )); } @@ -2279,13 +2348,16 @@ fn render_spillover_annotation(width: u16) -> Line<'static> { // Matches the model-facing preview footer (truncate.rs) and the existing // "Alt+V opens …" hint style (#3256): one quiet line, no handles or paths. let affordance = format!( - "Output shortened — {}", + "Output shortened \u{00B7} {}", crate::tui::key_shortcuts::tool_details_shortcut_action_hint("output") ); - Line::from(Span::styled( - truncate_text(&affordance, usize::from(width).max(8)), + let room = usize::from(width) + .saturating_sub(UnicodeWidthStr::width(TRANSCRIPT_RAIL)) + .max(8); + details_affordance_line( + &truncate_text(&affordance, room), Style::default().fg(palette::TEXT_MUTED).italic(), - )) + ) } /// Detect a truncated-output preview: the current model-facing footer (which @@ -2584,7 +2656,8 @@ fn status_symbol( ToolStatus::Running => { crate::tui::spinner::braille_spinner_frame(started_at, low_motion).to_string() } - ToolStatus::Success | ToolStatus::Hydrated => TOOL_DONE_SYMBOL.to_string(), + ToolStatus::Success => TOOL_DONE_SYMBOL.to_string(), + ToolStatus::Hydrated => crate::tui::glyphs::NEUTRAL.to_string(), ToolStatus::Warning => "!".to_string(), ToolStatus::Failed => TOOL_FAILED_SYMBOL.to_string(), } @@ -2659,10 +2732,11 @@ fn error_body_style(severity: crate::error_taxonomy::ErrorSeverity) -> Style { } /// Render an engine error without markdown interpretation. The live transcript -/// always advertises the dedicated full-error pager: terminal height, scroll -/// position, and adjacent tool cards can otherwise make a multiline recovery -/// instruction look like a clipped one-line failure. Transcript/pager mode -/// omits the recursive affordance while preserving every character. +/// advertises the dedicated full-error pager once the error wraps past four +/// rows: terminal height, scroll position, and adjacent tool cards can +/// otherwise make a multiline recovery instruction look like a clipped +/// one-line failure. Transcript/pager mode omits the recursive affordance +/// while preserving every character. fn render_error_message( message: &str, severity: crate::error_taxonomy::ErrorSeverity, @@ -2691,7 +2765,7 @@ fn render_error_message( for line in lines.iter_mut().skip(1) { line.spans.insert(0, Span::styled(rail.clone(), rail_style)); } - if show_full_error_affordance { + if show_full_error_affordance && lines.len() > 4 { lines.push(details_affordance_line( &crate::tui::key_shortcuts::tool_details_shortcut_action_hint("full error"), Style::default().fg(palette::TEXT_MUTED).italic(), @@ -2769,9 +2843,11 @@ fn render_tool_header_with_family_and_summary( ), Span::styled(format!("{glyph} "), glyph_style), Span::styled(verb.to_string(), tool_title_style(status)), - Span::styled(" ", Style::default()), - Span::styled(state_owned, tool_status_style(status, family)), ]; + if !state_owned.is_empty() { + spans.push(Span::styled(" ", Style::default())); + spans.push(Span::styled(state_owned, tool_status_style(status, family))); + } // #4148: don't let the summary echo the verb it sits next to — an // identity/summary that resolves to the family word itself would render a @@ -2791,6 +2867,29 @@ fn render_tool_header_with_family_and_summary( Line::from(spans) } +fn header_shows_in_full(header: &Line<'static>, summary: &str, available: usize) -> bool { + normalize_header_summary(summary).is_none_or(|summary| { + crate::tui::ui_text::text_display_width(&summary) <= TOOL_HEADER_SUMMARY_LIMIT + }) && header.width() <= available +} + +fn header_repeats_args( + header: &Line<'static>, + header_summary: Option<&str>, + args: &str, + available: usize, +) -> bool { + let args = args.trim(); + let shown = match args.split_once(": ") { + Some((_, value)) if !args.contains(", ") => value.trim(), + _ => args, + }; + header_summary.is_some_and(|summary| { + (summary == shown || summary.ends_with(&format!(" \u{00B7} {shown}"))) + && header_shows_in_full(header, summary, available) + }) +} + fn normalize_header_summary(summary: &str) -> Option { let normalized = summary .split_whitespace() @@ -2819,7 +2918,7 @@ pub(crate) fn running_status_label_with_elapsed(elapsed_secs: u64) -> String { pub(crate) fn stale_shell_status_label(elapsed_since_output_ms: u64) -> String { format!( - "running · stale · no output {}", + "running · no output for {}", codewhale_command_contract::elapsed::format_elapsed_ms(elapsed_since_output_ms) ) } @@ -2979,7 +3078,7 @@ fn tool_detail_label_style() -> Style { /// its border colour follows it. In-flight takes the action accent, a settled /// success recedes into muted text so finished work stops competing for the /// eye, and only warning and failure keep a loud colour. `Hydrated` is a -/// stalled "tool loaded — retry required", not live work, so it takes the hint +/// stalled "loaded, not run", not live work, so it takes the hint /// colour instead of borrowing the running accent and reading as in-flight. /// /// The glyph and status word use the same lifecycle ink; the glyph shape @@ -3002,13 +3101,13 @@ fn tool_glyph_color( tool_rail_color(status) } -fn tool_status_label(status: ToolStatus) -> &'static str { +pub(crate) fn tool_status_label(status: ToolStatus) -> &'static str { match status { ToolStatus::Running => "running", ToolStatus::Success => "done", - ToolStatus::Hydrated => "tool loaded - retry required", + ToolStatus::Hydrated => "loaded, not run", ToolStatus::Warning => "issue", - ToolStatus::Failed => "issue", + ToolStatus::Failed => "failed", } } diff --git a/crates/tui/src/tui/history/checklist.rs b/crates/tui/src/tui/history/checklist.rs index da7358c2bd..9ab71a46a9 100644 --- a/crates/tui/src/tui/history/checklist.rs +++ b/crates/tui/src/tui/history/checklist.rs @@ -5,10 +5,11 @@ use ratatui::text::{Line, Span}; use serde_json::Value; use unicode_width::UnicodeWidthStr; +use codewhale_localization::{Locale, MessageId, tr}; use codewhale_palette as palette; use super::{ - RenderMode, TRANSCRIPT_RAIL, ToolStatus, render_card_detail_line_single, render_compact_kv, + RenderMode, TRANSCRIPT_RAIL, ToolStatus, render_card_detail_line_single, render_tool_header_with_family_and_summary, tool_status_label, tool_value_style, truncate_text, wrap_text, }; @@ -136,6 +137,7 @@ pub(super) fn render_checklist_change_card( change: &ChecklistChange, width: u16, low_motion: bool, + locale: Locale, ) -> Vec> { let mut lines = Vec::new(); let header_summary = format!( @@ -168,7 +170,7 @@ pub(super) fn render_checklist_change_card( UnicodeWidthStr::width(TRANSCRIPT_RAIL) + UnicodeWidthStr::width(prefix.as_str()); let id_label = format!("Todo #{}", change.id); let arrow = " \u{2192} "; - let status_label = change.status.clone(); + let status_label = checklist_status_label(&change.status, locale); let title_budget = usize::from(width) .saturating_sub(prefix_width) .saturating_sub(UnicodeWidthStr::width(id_label.as_str())) @@ -197,7 +199,7 @@ pub(super) fn render_checklist_change_card( lines.push(render_card_detail_line_single( None, &format!( - "{} item{}; {}", + "{} item{} \u{00B7} {}", snapshot.total, if snapshot.total == 1 { "" } else { "s" }, crate::tui::key_shortcuts::tool_details_shortcut_action_hint("list") @@ -207,6 +209,18 @@ pub(super) fn render_checklist_change_card( lines } +fn checklist_status_label(status: &str, locale: Locale) -> String { + use crate::tools::todo::TodoStatus; + let id = match TodoStatus::from_str(status) { + Some(TodoStatus::Pending) => MessageId::TodoStatusPending, + Some(TodoStatus::InProgress) => MessageId::TodoStatusInProgress, + Some(TodoStatus::Completed) => MessageId::TodoStatusCompleted, + Some(TodoStatus::Cancelled) => MessageId::TodoStatusCancelled, + None => return status.to_string(), + }; + tr(locale, id).into_owned() +} + fn checklist_status_marker(status: &str) -> (&'static str, Color) { match status.to_ascii_lowercase().as_str() { "completed" | "done" => ("\u{2611}", palette::STATUS_SUCCESS), // ☑ @@ -241,12 +255,6 @@ pub(super) fn render_checklist_card( None, low_motion, )); - lines.extend(render_compact_kv( - "checklist", - name, - tool_value_style(), - width, - )); let cap = match mode { RenderMode::Live => CHECKLIST_LIVE_ITEM_LIMIT, @@ -286,7 +294,7 @@ pub(super) fn render_checklist_card( lines.push(render_card_detail_line_single( None, &format!( - "+{omitted} more; {}", + "+{omitted} more \u{00B7} {}", crate::tui::key_shortcuts::tool_details_shortcut_action_hint("list") ), Style::default().fg(palette::TEXT_DIM), diff --git a/crates/tui/src/tui/history/file_mutation.rs b/crates/tui/src/tui/history/file_mutation.rs index 5671c01d86..7ee9a8081e 100644 --- a/crates/tui/src/tui/history/file_mutation.rs +++ b/crates/tui/src/tui/history/file_mutation.rs @@ -6,8 +6,8 @@ use std::path::{Component, Path}; -use ratatui::style::{Modifier, Style}; -use ratatui::text::{Line, Span}; +use ratatui::style::Style; +use ratatui::text::Line; use serde_json::Value; use crate::settings::InlineDiffMode; @@ -166,23 +166,9 @@ impl FileMutationReceipt { pub fn render_inline(&self, width: u16, mode: InlineDiffMode) -> Vec> { match mode { - InlineDiffMode::Off => vec![exact_evidence_hint()], - InlineDiffMode::Summary => vec![ - Line::from(Span::styled( - self.semantic_summary(), - Style::default() - .fg(palette::TEXT_PRIMARY) - .add_modifier(Modifier::BOLD), - )), - exact_evidence_hint(), - ], + InlineDiffMode::Off | InlineDiffMode::Summary => vec![exact_evidence_hint()], InlineDiffMode::Full => { - let mut lines = vec![Line::from(Span::styled( - self.semantic_summary(), - Style::default() - .fg(palette::TEXT_PRIMARY) - .add_modifier(Modifier::BOLD), - ))]; + let mut lines = Vec::new(); if !self.display_diff.trim().is_empty() { let rendered = diff_render::render_diff_body_bounded( &self.display_diff, @@ -412,8 +398,8 @@ mod tests { assert!(!full_text.contains("summary:"), "{full_text}"); let summary = plain(&receipt.render_inline(80, InlineDiffMode::Summary)); - assert!(summary.contains("Created src/lib.rs"), "{summary}"); - assert!(summary.contains("+30 -0"), "{summary}"); + assert!(!summary.contains("Created src/lib.rs"), "{summary}"); + assert!(!summary.contains("+30 -0"), "{summary}"); assert!(!summary.contains("line 0"), "{summary}"); assert!(summary.contains(":change"), "{summary}"); diff --git a/crates/tui/src/tui/history/tests.rs b/crates/tui/src/tui/history/tests.rs index ef4f7394c5..e098af60a2 100644 --- a/crates/tui/src/tui/history/tests.rs +++ b/crates/tui/src/tui/history/tests.rs @@ -999,7 +999,7 @@ fn the_copy_prefix_skips_every_decoration_and_keeps_the_payload() { )); let copied = slice_visible_columns(&body, header.copy_prefix_width, text_visible_width(&body)); assert!( - copied.contains("run Done"), + copied.contains("run done"), "receipt text was clipped away: {copied:?}" ); for glyph in decorations { @@ -1414,16 +1414,17 @@ fn a_card_verb_agrees_with_its_own_label_in_every_locale() { for (label, expected_en, expected_zh, forbidden_en) in [ ( "Searching for `TranscriptScroll`", - "find Done", + "find done", "find 完成", - "read Done", + "read done", ), - ("Reading src/foo.rs", "read Done", "read 完成", "find Done"), + ("Reading src/foo.rs", "read done", "read 完成", "find done"), ] { let cell = super::ExploringCell { entries: vec![super::ExploringEntry { label: label.to_string(), status: ToolStatus::Success, + error: None, }], }; @@ -1466,7 +1467,7 @@ fn receipts_count_only_what_they_actually_counted() { use crate::tui::widgets::tool_card::ToolFamily; use codewhale_localization::Locale; - for (locale, done, unit) in [(Locale::En, "Done", "line"), (Locale::ZhHans, "完成", "行")] { + for (locale, done, unit) in [(Locale::En, "done", "line"), (Locale::ZhHans, "完成", "行")] { let label = |family, status, output| { super::tool_receipt_label(family, status, Some(output), locale) }; @@ -1548,7 +1549,7 @@ fn shell_headers_stay_truthful_through_the_output_formatters() { cell.duration_ms = Some(42); for (locale, done, unit) in [ - (Locale::En, "Done", "lines"), + (Locale::En, "done", "lines"), (Locale::ZhHans, "完成", "行"), ] { let header = line_text(&cell.render_with_locale(80, true, RenderMode::Live, locale)[0]); @@ -2083,11 +2084,12 @@ fn a_checklist_update_shows_only_the_item_that_changed() { }, 80, true, + codewhale_localization::Locale::En, ); assert!(lines.len() >= 3, "header, change, summary: {}", lines.len()); let change = line_text(&lines[1]); - for needle in ["#2", "Write the test", "in_progress"] { + for needle in ["#2", "Write the test", "in progress"] { assert!(change.contains(needle), "missing {needle:?}: {change:?}"); } for other in ["Land the PR", "Read the spec"] { @@ -2123,6 +2125,7 @@ fn a_checklist_update_shows_only_the_item_that_changed() { }, 80, true, + codewhale_localization::Locale::En, ); let change = line_text(&lines[1]); assert!(change.contains("#99") && change.contains("(missing title)")); @@ -2194,7 +2197,7 @@ fn fan_out_prompts_replace_the_inline_argument_summary() { ); let mut plain = generic_tool("file_search", ToolStatus::Running); - plain.input_summary = Some("query: foo".to_string()); + plain.input_summary = Some("query: foo, path: src".to_string()); let text = lines_text(&HistoryCell::Tool(ToolCell::Generic(plain)).lines(80)); assert!( text.contains("query: foo"), @@ -2563,7 +2566,7 @@ fn a_collapsed_run_summary_names_what_actually_happened() { ..Default::default() } )), - "Explored 4 files, 1 search: read_file, list_dir" + "Explored 4 files, 1 search: read file, list dir" ); assert_eq!( @@ -2575,7 +2578,7 @@ fn a_collapsed_run_summary_names_what_actually_happened() { ..Default::default() } )), - "Explored 2 files: read_file, ran 2 commands: run_tests, validate_data", + "Explored 2 files: read file, ran 2 commands: run tests, validate data", "each clause lists only its own families" ); @@ -2604,7 +2607,7 @@ fn a_collapsed_run_summary_names_what_actually_happened() { assert_eq!(commands[0].activity.commands, 3); assert_eq!( super::tool_run_summary(&commands[0]), - "Ran 3 commands: run_tests, run_verifiers, validate_data" + "Ran 3 commands: run tests, run verifiers, validate data" ); let git = super::detect_tool_runs( @@ -2618,7 +2621,7 @@ fn a_collapsed_run_summary_names_what_actually_happened() { assert_eq!(git[0].activity.files, 3); assert_eq!( super::tool_run_summary(&git[0]), - "Explored 3 files: git_log, git_show, git_blame" + "Explored 3 files: git log, git show, git blame" ); } @@ -2797,6 +2800,7 @@ fn exploring_cell_status_keeps_the_loudest_terminal_state() { .map(|status| ExploringEntry { label: "Reading src/foo.rs".to_string(), status: *status, + error: None, }) .collect(), }; diff --git a/crates/tui/src/tui/history/tool_output.rs b/crates/tui/src/tui/history/tool_output.rs index 84c85fd077..3a52d8967d 100644 --- a/crates/tui/src/tui/history/tool_output.rs +++ b/crates/tui/src/tui/history/tool_output.rs @@ -423,7 +423,7 @@ fn render_preserved_output_mode( if omitted > 0 { lines.push(details_affordance_line( &format!( - "{omitted} lines omitted; {}", + "{omitted} lines omitted \u{00B7} {}", crate::tui::key_shortcuts::tool_details_shortcut_action_hint("output") ), Style::default().fg(palette::TEXT_MUTED), diff --git a/crates/tui/src/tui/history/tool_run.rs b/crates/tui/src/tui/history/tool_run.rs index 08b2c84a87..e3dad10549 100644 --- a/crates/tui/src/tui/history/tool_run.rs +++ b/crates/tui/src/tui/history/tool_run.rs @@ -312,12 +312,11 @@ pub fn tool_run_summary(run: &ToolRun) -> String { } fn activity_family_summary(run: &ToolRun, activities: &[ToolRunActivity]) -> Option { - let mut families = Vec::new(); + let mut families: Vec = Vec::new(); for family in &run.tool_families { - if activities.contains(&classify_tool_name_activity(family)) - && !families.iter().any(|existing| existing == family) - { - families.push(family.as_str()); + let label = family.replace('_', " "); + if activities.contains(&classify_tool_name_activity(family)) && !families.contains(&label) { + families.push(label); } } diff --git a/crates/tui/src/tui/markdown_render.rs b/crates/tui/src/tui/markdown_render.rs index 0dfa3d194c..f005eee13c 100644 --- a/crates/tui/src/tui/markdown_render.rs +++ b/crates/tui/src/tui/markdown_render.rs @@ -745,7 +745,12 @@ pub(crate) fn render_parsed_tagged_with_palette( let style = Style::default() .fg(palette::WHALE_ACTION) .add_modifier(Modifier::BOLD); - out.extend(render_wrapped_line_tagged(text, width, style, false, false)); + out.extend(render_line_with_links_tagged( + text, + width, + style, + link_style(), + )); } Block::HeadingRule => { out.push(RenderedMarkdownLine { @@ -1075,10 +1080,11 @@ fn last_plain_break_pos(text: &str) -> Option { fn parse_heading(line: &str) -> Option<(usize, &str)> { let trimmed = line.trim_start(); let hashes = trimmed.chars().take_while(|c| *c == '#').count(); - if hashes == 0 { + let rest = &trimmed[hashes..]; + if !(1..=6).contains(&hashes) || !(rest.is_empty() || rest.starts_with(char::is_whitespace)) { return None; } - let text = trimmed[hashes..].trim(); + let text = rest.trim(); if text.is_empty() { None } else { @@ -1362,54 +1368,6 @@ fn render_wrapped_code_spans_tagged( .collect() } -fn render_wrapped_line_tagged( - line: &str, - width: usize, - style: Style, - indent_code: bool, - is_code: bool, -) -> Vec { - let prefix = if indent_code { " " } else { "" }; - let prefix_width = prefix.width(); - let available = width.saturating_sub(prefix_width).max(1); - // Code blocks must preserve leading whitespace (indentation is semantic). - // Use hard character-width wrapping instead of word-wrap. - let wrapped = if indent_code { - wrap_code_line(line, available) - } else { - wrap_text(line, available) - }; - let mut out = Vec::new(); - - let last_index = wrapped.len().saturating_sub(1); - for (idx, chunk) in wrapped.into_iter().enumerate() { - let line = if idx == 0 { - Line::from(vec![Span::raw(prefix), Span::styled(chunk, style)]) - } else { - Line::from(vec![ - Span::raw(" ".repeat(prefix_width)), - Span::styled(chunk, style), - ]) - }; - let copy_separator_after = if idx == last_index { - CopyLineSeparator::Newline - } else if is_code { - CopyLineSeparator::None - } else { - CopyLineSeparator::Space - }; - out.push(RenderedMarkdownLine { - line, - links: Vec::new(), - is_code, - copy_prefix_width: if indent_code { prefix_width } else { 0 }, - copy_separator_after, - }); - } - - out -} - fn render_list_line_tagged( bullet: &str, text: &str, @@ -2108,18 +2066,21 @@ fn wrap_cell_text(cell: &str, col_width: usize) -> Vec { lines } -fn render_table_row(cells: &[String], width: usize, base_style: Style) -> Vec> { - if cells.is_empty() { - return vec![Line::from("")]; - } - let col_width = (width.saturating_sub(3 * cells.len() + 1)) / cells.len(); - let col_width = col_width.max(4); +fn render_table_row( + cells: &[String], + num_cols: usize, + width: usize, + base_style: Style, +) -> Vec> { + let col_width = table_col_width(num_cols, width); let sep_style = Style::default().fg(palette::TEXT_DIM); // Wrap each cell into one or more visual segments. The row's visual // height equals the tallest column. Cells that wrap to fewer segments // get blank-padded continuation lines so column separators stay aligned. - let wrapped: Vec> = cells.iter().map(|c| wrap_cell_text(c, col_width)).collect(); + let wrapped: Vec> = (0..num_cols) + .map(|i| wrap_cell_text(cells.get(i).map_or("", String::as_str), col_width)) + .collect(); let row_height = wrapped.iter().map(Vec::len).max().unwrap_or(1).max(1); let mut lines: Vec> = Vec::with_capacity(row_height); @@ -2134,7 +2095,7 @@ fn render_table_row(cells: &[String], width: usize, base_style: Style) -> Vec
  • Vec< ) }; - for i in 0..blocks.len() { - match &blocks[i] { + let header_end = blocks + .iter() + .position(|b| matches!(b, Block::TableSeparator)) + .unwrap_or(0); + + for (i, block) in blocks.iter().enumerate() { + match block { Block::TableRow(cells) => { - lines.extend(render_table_row(cells, width, base_style)); - if i + 1 < blocks.len() && matches!(&blocks[i + 1], Block::TableRow(_)) { - lines.push(mid_border()); - } + let style = if i < header_end { + base_style.add_modifier(Modifier::BOLD) + } else { + base_style + }; + lines.extend(render_table_row(cells, num_cols, width, style)); } Block::TableSeparator => { lines.push(mid_border()); @@ -2274,86 +2242,11 @@ fn markdown_grapheme_width(grapheme: &str, col: usize) -> usize { grapheme.width() } -/// Hard-wrap a code line at `width` display columns, preserving all -/// whitespace (including leading indentation). Unlike [`wrap_text`], this -/// does not split on word boundaries — code indentation is semantic. -fn wrap_code_line(line: &str, width: usize) -> Vec { - if width == 0 || line.is_empty() { - return vec![line.to_string()]; - } - let mut chunks = Vec::new(); - let mut current = String::new(); - let mut current_width = 0usize; - - for grapheme in line.graphemes(true) { - let grapheme_width = markdown_grapheme_width(grapheme, current_width); - if current_width + grapheme_width > width && !current.is_empty() { - chunks.push(current); - current = String::new(); - current_width = 0; - } - current.push_str(grapheme); - current_width += grapheme_width; - } - chunks.push(current); - chunks -} - -fn wrap_text(text: &str, width: usize) -> Vec { - if width == 0 { - return vec![text.to_string()]; - } - let mut lines = Vec::new(); - let mut current = String::new(); - let mut current_width = 0; - - for word in text.split_whitespace() { - let word_width = word.width(); - // If this single word is wider than the entire line, hard-break it - // at grapheme boundaries so wrapping always makes progress - // (#1344, #1351). Without this, long URLs / paths / hashes overflow - // the right edge silently. - if word_width > width { - if !current.is_empty() { - lines.push(std::mem::take(&mut current)); - current_width = 0; - } - push_word_breaking_graphemes(word, width, &mut current, &mut current_width, &mut lines); - continue; - } - let additional = if current.is_empty() { - word_width - } else { - word_width + 1 - }; - if current_width + additional > width && !current.is_empty() { - lines.push(current); - current = word.to_string(); - current_width = word_width; - } else { - if !current.is_empty() { - current.push(' '); - current_width += 1; - } - current.push_str(word); - current_width += word_width; - } - } - - if current.is_empty() { - lines.push(String::new()); - } else { - lines.push(current); - } - - lines -} - /// Push graphemes from `word` into `current`, flushing to `lines` when the /// running display width would exceed `width`. String-level Unicode width /// matches Ratatui for emoji and combining sequences. -/// Used by `wrap_text` and `wrap_cell_text` so a word longer than the -/// allotted width never silently overflows the right edge. +/// Used by `wrap_cell_text` so a word longer than the allotted width never +/// silently overflows the right edge. fn push_word_breaking_graphemes( word: &str, width: usize, @@ -3133,38 +3026,6 @@ mod tests { ); } - #[test] - fn wrap_code_line_preserves_leading_whitespace() { - // A short line must not be modified. - assert_eq!(wrap_code_line(" let x = 1;", 80), vec![" let x = 1;"]); - - // A line that exceeds the width must be hard-wrapped, keeping the - // leading whitespace on the first chunk. - let chunks = wrap_code_line(" abcdefgh", 8); - assert_eq!(chunks[0], " abcd", "first chunk keeps leading spaces"); - assert_eq!(chunks[1], "efgh"); - - // Empty line produces one empty chunk. - assert_eq!(wrap_code_line("", 80), vec![""]); - } - - #[test] - fn wrap_code_line_tab_counts_toward_width() { - // tab (8 cols) + "xy" (2 cols) = 10 ≤ 10 — fits on one line. - let chunks = wrap_code_line("\txy", 10); - assert_eq!(chunks, vec!["\txy"], "tab + 2 chars fits in width 10"); - - // tab (8 cols) + "x" (1 col) = 9 ≤ 9 — "x" fits; "y" overflows. - let chunks = wrap_code_line("\txy", 9); - assert_eq!(chunks[0], "\tx", "tab + first char fits exactly"); - assert_eq!(chunks[1], "y", "second char wraps"); - - // tab alone (8 cols) fits in width 8; the next "x" overflows. - let chunks = wrap_code_line("\tx", 8); - assert_eq!(chunks[0], "\t"); - assert_eq!(chunks[1], "x"); - } - #[test] fn markdown_grapheme_width_uses_tab_stop_and_string_width() { // At column 0 a tab fills to column 8. @@ -3785,12 +3646,12 @@ mod tests { // ─── Paragraph wrap regression suite (#1344, #1351) ──────────────────── // - // The bug: paragraph wrap (render_line_with_links) and code-block wrap - // (wrap_text) are word-based. A single word wider than the available - // width was placed alone on a line and silently overflowed the right - // edge of the transcript. Long URLs / paths / hashes / no-whitespace - // CJK runs all hit this. The fix hard-breaks overlong words at - // grapheme boundaries; these tests pin that across widths 40/60/80/120. + // The bug: paragraph wrap (render_line_with_links) is word-based. A + // single word wider than the available width was placed alone on a line + // and silently overflowed the right edge of the transcript. Long URLs / + // paths / hashes / no-whitespace CJK runs all hit this. The fix + // hard-breaks overlong words at grapheme boundaries; these tests pin + // that across widths 40/60/80/120. fn rendered_widths(rendered: &[Line<'static>]) -> Vec { rendered @@ -3907,24 +3768,6 @@ mod tests { assert_eq!(combined.matches('x').count(), 150); } - #[test] - fn wrap_text_breaks_overlong_word_for_code_blocks() { - // The standalone code-block wrap (wrap_text) had the same overflow - // bug; pin the fix at widths 40 and 80. - for &width in &[40usize, 80] { - let long = "z".repeat(200); - let lines = wrap_text(&long, width); - for line in &lines { - assert!( - line.width() <= width, - "wrap_text line {line:?} exceeds {width}" - ); - } - let combined: String = lines.join(""); - assert_eq!(combined.matches('z').count(), 200); - } - } - #[test] fn wrap_cell_text_already_handled_long_words_remains_correct() { // Regression guard for the v0.8.25 table-cell fix. After consolidating @@ -4022,32 +3865,6 @@ mod tests { } } - #[test] - fn lower_level_wrap_text_keeps_unicode_runs_within_qa_widths() { - let cases = [ - ("cjk", "中".repeat(140)), - ("emoji", "😀".repeat(110)), - ("combining", "e\u{301}".repeat(140)), - ]; - - for (label, input) in cases { - for &width in &[80usize, 100, 120] { - let lines = wrap_text(&input, width); - for line in &lines { - assert!( - line.width() <= width, - "{label} width={width}: wrap_text line {line:?} exceeds budget" - ); - } - let combined: String = lines.join(""); - assert_eq!( - combined, input, - "{label} width={width}: wrap_text changed content" - ); - } - } - } - #[test] fn table_render_keeps_cjk_cells_within_qa_widths() { let cjk = "界".repeat(80); diff --git a/crates/tui/src/tui/mouse_ui.rs b/crates/tui/src/tui/mouse_ui.rs index 4c8ea199bb..edc4d7c5d1 100644 --- a/crates/tui/src/tui/mouse_ui.rs +++ b/crates/tui/src/tui/mouse_ui.rs @@ -749,6 +749,8 @@ pub(crate) fn handle_mouse_event(app: &mut App, mouse: MouseEvent) -> Vec { + if let Some(id) = command.strip_prefix("/jobs show ") + && app.task_panel.iter().any(|entry| { + entry.id == id && crate::tui::background_indicator::is_live_shell_entry(entry) + }) + { + stop = Some( + row( + app.tr(MessageId::CtxMenuStopWork).into_owned(), + SidebarRowAction::Command(format!("/jobs cancel {id}")), + ) + .confirm(confirm()), + ); + } let label = app .tr(MessageId::CtxMenuRunCommand) .replace("{command}", &command); @@ -1748,12 +1763,16 @@ pub(crate) fn apply_context_menu_action( } } } - ContextMenuAction::CopyText { text } => { - app.status_message = Some(match app.clipboard.write_text_status(&text) { - Ok(transport) => copy_receipt(app, transport, app.tr(MessageId::ClipboardCopied)), - Err(error) => format!("Copy failed: {error}"), - }); - } + ContextMenuAction::CopyText { text } => match app.clipboard.write_text_status(&text) { + Ok(transport) => { + let receipt = copy_receipt(app, transport, app.tr(MessageId::ClipboardCopied)); + app.push_status_toast(receipt, StatusToastLevel::Info, None); + } + Err(error) => { + let receipt = copy_failed_receipt(app, error); + app.push_status_toast(receipt, StatusToastLevel::Error, None); + } + }, ContextMenuAction::ToggleWindowPin => { crate::tui::window_control::toggle_pin(app); } @@ -1944,6 +1963,11 @@ pub(crate) fn copy_receipt( } } +pub(crate) fn copy_failed_receipt(app: &App, error: impl std::fmt::Display) -> String { + app.tr(MessageId::ClipboardCopyFailed) + .replace("{error}", &error.to_string()) +} + /// Ctrl+X on a composer selection. The text is deleted only after a native /// clipboard confirmed the copy; an OSC 52 / tmux copy is never confirmed, /// so the text stays and the receipt says why. @@ -1954,15 +1978,20 @@ pub(crate) fn cut_selection(app: &mut App) { } match app.clipboard.write_text_status(&sel) { Ok(crate::tui::clipboard::CopyTransport::Native) => { - app.push_status_toast("Cut to clipboard", StatusToastLevel::Info, None); + app.push_status_toast( + app.tr(MessageId::ClipboardCopied), + StatusToastLevel::Info, + None, + ); app.delete_selection(); } Ok(crate::tui::clipboard::CopyTransport::Terminal) => { let receipt = app.tr(MessageId::ClipboardCutKeptText).into_owned(); app.push_status_toast(receipt, StatusToastLevel::Info, None); } - Err(_) => { - app.push_status_toast("Cut failed", StatusToastLevel::Error, None); + Err(error) => { + let receipt = copy_failed_receipt(app, error); + app.push_status_toast(receipt, StatusToastLevel::Error, None); } } } @@ -2053,10 +2082,14 @@ pub(crate) fn copy_active_selection(app: &mut App) { if !sel.is_empty() { match app.clipboard.write_text_status(&sel) { Ok(transport) => { - app.status_message = Some(copy_receipt(app, transport, "Selection copied")); + let receipt = copy_receipt(app, transport, app.tr(MessageId::ClipboardCopied)); + app.push_status_toast(receipt, StatusToastLevel::Info, None); app.clear_selection(); } - Err(_) => app.status_message = Some("Copy failed".to_string()), + Err(error) => { + let receipt = copy_failed_receipt(app, error); + app.push_status_toast(receipt, StatusToastLevel::Error, None); + } } return; } @@ -2078,25 +2111,22 @@ pub(crate) fn copy_active_selection(app: &mut App) { .map(|text| (text, None)) }); if let Some((text, markdown_cells)) = payload { - let written = app.clipboard.write_text_status(&text); - if let Ok(crate::tui::clipboard::CopyTransport::Terminal) = written { - app.status_message = Some(copy_receipt( - app, - crate::tui::clipboard::CopyTransport::Terminal, - "", - )); - } else if written.is_ok() { - match markdown_cells { - Some(cells) => { - let toast = app + match app.clipboard.write_text_status(&text) { + Ok(transport) => { + let receipt = match (transport, markdown_cells) { + (crate::tui::clipboard::CopyTransport::Native, Some(cells)) => app .tr(MessageId::SelectionCopiedAsMarkdown) - .replace("{count}", &cells.to_string()); - app.push_status_toast(toast, StatusToastLevel::Info, None); - } - None => app.status_message = Some("Selection copied".to_string()), + .replace("{count}", &cells.to_string()), + (transport, _) => { + copy_receipt(app, transport, app.tr(MessageId::ClipboardCopied)) + } + }; + app.push_status_toast(receipt, StatusToastLevel::Info, None); + } + Err(error) => { + let receipt = copy_failed_receipt(app, error); + app.push_status_toast(receipt, StatusToastLevel::Error, None); } - } else { - app.status_message = Some("Copy failed".to_string()); } } else { clear_transcript_selection(app); @@ -3315,7 +3345,10 @@ mod tests { select(&mut app); super::apply_context_menu_action(&mut app, ContextMenuAction::CopySelection); assert_eq!(app.clipboard.last_written_text(), Some("hello")); - assert_eq!(app.status_message.as_deref(), Some("Selection copied")); + assert_eq!( + app.status_toasts.back().map(|toast| toast.text.as_str()), + Some("Copied to the clipboard") + ); select(&mut app); super::apply_context_menu_action(&mut app, ContextMenuAction::OpenSelection); @@ -3392,7 +3425,7 @@ mod tests { /// Ctrl+X deletes the selection only when a native clipboard confirmed /// the copy. A terminal (OSC 52 / tmux) copy keeps the text and says why; - /// a failed copy keeps it and says the cut failed. + /// a failed copy keeps it and says the copy failed. #[test] fn cut_deletes_only_after_a_native_copy() { fn select_all(app: &mut App, text: &str) { @@ -3409,7 +3442,7 @@ mod tests { super::cut_selection(&mut app); assert_eq!(app.clipboard.last_written_text(), Some("hello")); assert_eq!(app.input, "", "a native copy cuts"); - assert_eq!(last_toast(&app), Some("Cut to clipboard")); + assert_eq!(last_toast(&app), Some("Copied to the clipboard")); app.clipboard = crate::tui::clipboard::ClipboardHandler::terminal_only_for_test(); select_all(&mut app, "kept"); @@ -3429,7 +3462,11 @@ mod tests { select_all(&mut app, "also kept"); super::cut_selection(&mut app); assert_eq!(app.input, "also kept", "a failed copy keeps the text"); - assert_eq!(last_toast(&app), Some("Cut failed")); + assert!( + last_toast(&app).is_some_and(|toast| toast.starts_with("Clipboard copy failed: ")), + "{:?}", + last_toast(&app) + ); } /// A right-click on a row's inline stop zone opens the row's own menu; @@ -3471,6 +3508,10 @@ mod tests { /// the text was sent to the terminal, not that it was copied. #[test] fn copy_receipts_name_the_transport() { + fn last_toast(app: &App) -> Option<&str> { + app.status_toasts.back().map(|toast| toast.text.as_str()) + } + let mut app = create_test_app(); super::apply_context_menu_action( &mut app, @@ -3479,10 +3520,7 @@ mod tests { }, ); assert_eq!(app.clipboard.last_written_text(), Some("agent_1")); - assert_eq!( - app.status_message.as_deref(), - Some("Copied to the clipboard") - ); + assert_eq!(last_toast(&app), Some("Copied to the clipboard")); app.clipboard = crate::tui::clipboard::ClipboardHandler::terminal_only_for_test(); super::apply_context_menu_action( @@ -3492,7 +3530,7 @@ mod tests { }, ); assert_eq!( - app.status_message.as_deref(), + last_toast(&app), Some("Sent to the terminal clipboard (terminals do not confirm it)") ); @@ -3510,7 +3548,7 @@ mod tests { app.cursor_position = 5; super::apply_context_menu_action(&mut app, ContextMenuAction::CopySelection); assert_eq!( - app.status_message.as_deref(), + last_toast(&app), Some("Sent to the terminal clipboard (terminals do not confirm it)") ); @@ -3522,11 +3560,9 @@ mod tests { }, ); assert!( - app.status_message - .as_deref() - .is_some_and(|status| status.starts_with("Copy failed")), + last_toast(&app).is_some_and(|toast| toast.starts_with("Clipboard copy failed: ")), "{:?}", - app.status_message + last_toast(&app) ); } diff --git a/crates/tui/src/tui/mouse_ui/primary_tests.rs b/crates/tui/src/tui/mouse_ui/primary_tests.rs index 12a6a4ec7f..61fc93ac79 100644 --- a/crates/tui/src/tui/mouse_ui/primary_tests.rs +++ b/crates/tui/src/tui/mouse_ui/primary_tests.rs @@ -281,8 +281,11 @@ fn transcript_copy_falls_back_to_rendered_text_when_markdown_is_off() { let toasts_before = app.status_toasts.len(); copy_active_selection(&mut app); assert_eq!(app.clipboard.last_written_text(), Some(expected.as_str())); - assert_eq!(app.status_message.as_deref(), Some("Selection copied")); - assert_eq!(app.status_toasts.len(), toasts_before); + assert_eq!(app.status_toasts.len(), toasts_before + 1); + assert_eq!( + app.status_toasts.back().map(|toast| toast.text.as_str()), + Some("Copied to the clipboard") + ); } #[test] diff --git a/crates/tui/src/tui/pager.rs b/crates/tui/src/tui/pager.rs index 47ad8cc3fb..2c5da0b6bb 100644 --- a/crates/tui/src/tui/pager.rs +++ b/crates/tui/src/tui/pager.rs @@ -246,6 +246,8 @@ pub struct PagerView { /// (or key then Enter); Esc disarms before it closes the pager. destructive_action: Option, action_area: Cell>, + live_shell_job: Option, + follow: bool, } impl PagerView { @@ -270,9 +272,46 @@ impl PagerView { last_visible_height: Cell::new(0), destructive_action: None, action_area: Cell::new(None), + live_shell_job: None, + follow: false, } } + pub(crate) fn with_live_shell_job(mut self, job_id: impl Into) -> Self { + self.live_shell_job = Some(job_id.into()); + self + } + + pub(crate) fn live_shell_job(&self) -> Option<&str> { + self.live_shell_job.as_deref() + } + + pub(crate) fn replace_live_text(&mut self, text: &str) -> bool { + let page = self.current_page(); + if page.copy_text.as_deref() == Some(text) { + return false; + } + if self.scroll.get() >= self.max_scroll() { + self.follow = true; + } + let mut sanitized = String::with_capacity(text.len()); + crate::tui::osc8::strip_ansi_into(text, &mut sanitized); + let page = self.current_page_mut(); + page.source = PagerSource::Text(sanitized); + page.copy_text = Some(text.to_string()); + *page.rows.get_mut() = PagerRows::default(); + if !self.search_input.trim().is_empty() { + self.update_search_matches(); + } + true + } + + pub(crate) fn end_live_shell_job(&mut self) { + self.live_shell_job = None; + self.destructive_action = None; + self.action_area.set(None); + } + /// Attach a compact Markdown export (e.g. the #4108 turn handoff) that the /// `e` key copies to the clipboard. Only the Turn Inspector pager sets this; /// other pagers leave `e` inert. @@ -379,23 +418,28 @@ impl PagerView { self.search_index.set(0); self.search_mode = false; self.pending_g = false; + self.follow = false; } fn scroll_up(&mut self, amount: usize) { self.scroll.set(self.scroll.get().saturating_sub(amount)); + self.follow = false; } fn scroll_down(&mut self, amount: usize, max_scroll: usize) { self.scroll .set(self.scroll.get().saturating_add(amount).min(max_scroll)); + self.follow = self.live_shell_job.is_some() && self.scroll.get() >= max_scroll; } fn scroll_to_top(&mut self) { self.scroll.set(0); + self.follow = false; } fn scroll_to_bottom(&mut self, max_scroll: usize) { self.scroll.set(max_scroll); + self.follow = self.live_shell_job.is_some(); } /// Plain-text rendered body of the pager joined with `\n`. This reflects @@ -492,6 +536,7 @@ impl PagerView { fn jump_to_match(&mut self) { if let Some(&row) = self.search_matches.get_mut().get(self.search_index.get()) { self.scroll.set(row); + self.follow = false; } } @@ -867,7 +912,12 @@ impl ModalView for PagerView { let rows = page.rows.borrow(); let row_count = rows.plain.len(); let max_scroll = row_count.saturating_sub(visible_height); - let scroll = self.scroll.get().min(max_scroll); + let scroll = if self.follow { + self.scroll.set(max_scroll); + max_scroll + } else { + self.scroll.get().min(max_scroll) + }; let end = (scroll + visible_height).min(row_count); let mut visible_lines: Vec> = if row_count == 0 { vec![Line::from("")] @@ -1289,6 +1339,59 @@ mod tests { assert_eq!(p.scroll.get(), 0); } + #[test] + fn live_shell_job_pager_follows_new_output_until_scrolled_back() { + let body = |rows: usize| { + (0..rows) + .map(|row| format!("out-{row:03}")) + .collect::>() + .join("\n") + }; + let mut p = PagerView::from_text("Bash Job shell_1", &body(5), 40) + .with_copy_text(body(5)) + .with_live_shell_job("shell_1"); + prime_layout(&mut p, 12); + + assert!(p.replace_live_text(&body(60))); + prime_layout(&mut p, 12); + assert!(p.max_scroll() > 0); + assert_eq!(p.scroll.get(), p.max_scroll()); + + let _ = p.handle_key(key(KeyCode::Char('k'))); + let held = p.scroll.get(); + assert!(p.replace_live_text(&body(80))); + prime_layout(&mut p, 12); + assert_eq!(p.scroll.get(), held); + + let _ = p.handle_key(key(KeyCode::Char('G'))); + assert!(p.replace_live_text(&body(90))); + prime_layout(&mut p, 12); + assert_eq!(p.scroll.get(), p.max_scroll()); + assert!(!p.replace_live_text(&body(90))); + } + + #[test] + fn ending_a_live_shell_job_drops_stop() { + let mut p = make_pager(2) + .with_live_shell_job("shell_1") + .with_destructive_action( + 's', + "stop", + "confirm stop · Esc cancels", + ViewEvent::SidebarAgentCancel { + agent_id: "agent_1".to_string(), + }, + ); + p.end_live_shell_job(); + assert!(p.live_shell_job().is_none()); + for _ in 0..2 { + assert!(matches!( + p.handle_key(key(KeyCode::Char('s'))), + ViewAction::None + )); + } + } + #[test] fn shift_g_jumps_to_bottom() { let mut p = make_pager(50); diff --git a/crates/tui/src/tui/pet_watch/full.rs b/crates/tui/src/tui/pet_watch/full.rs index 4fef282a63..977018f492 100644 --- a/crates/tui/src/tui/pet_watch/full.rs +++ b/crates/tui/src/tui/pet_watch/full.rs @@ -3,7 +3,7 @@ //! durable world and audio. No prompt, worker or execution authority lives here. use super::{PetWatch, habitat}; use crate::{ - agent_roster::RosterState, + agent_roster::{AgentRosterRow, RosterState}, tools::subagent::AgentWorkerStatus, tui::{ app::App, @@ -41,8 +41,76 @@ fn theme(app: &App) -> Theme { .map_or(theme, |palette| theme.tui_palette(palette)) } +fn live_rows(app: &App) -> Vec { + use crate::tui::subagent_routing::{subagent_is_parked, worker_status_for_terminal_projection}; + let mut rows = app.current_agent_roster().to_vec(); + let name = |id: &str| app.agent_label_map.get(id).cloned(); + let blank = |id: &str, display_name: String| AgentRosterRow { + worker_id: id.to_string(), + display_name, + model: String::new(), + state: RosterState::Running, + status: AgentWorkerStatus::Running, + activity: None, + outcome: None, + millis: None, + input_tokens: None, + output_tokens: None, + cost_microusd: None, + steps_taken: 0, + parent_run_id: None, + run_id: id.to_string(), + }; + for agent in &app.subagent_cache { + let index = rows + .iter() + .position(|row| row.worker_id == agent.agent_id) + .unwrap_or_else(|| { + let display_name = name(&agent.agent_id) + .or_else(|| agent.nickname.clone()) + .unwrap_or_else(|| agent.name.clone()); + let usage = agent.usage.as_ref(); + rows.push(AgentRosterRow { + model: agent.model.clone(), + millis: Some(agent.duration_ms), + input_tokens: usage.and_then(|usage| usage.input_tokens), + output_tokens: usage.and_then(|usage| usage.output_tokens), + cost_microusd: usage.and_then(|usage| usage.cost_microusd), + steps_taken: agent.steps_taken, + parent_run_id: agent.parent_run_id.clone(), + ..blank(&agent.agent_id, display_name) + }); + rows.len() - 1 + }); + let row = &mut rows[index]; + row.status = agent + .worker_status + .unwrap_or_else(|| worker_status_for_terminal_projection(&agent.status)); + row.state = if subagent_is_parked(agent) { + RosterState::Parked + } else { + RosterState::from_worker(row.status) + }; + if row.state == RosterState::Running + && let Some(started) = agent.started_at + { + row.millis = Some(u64::try_from(started.elapsed().as_millis()).unwrap_or(u64::MAX)); + } + } + for (id, progress) in &app.agent_progress { + match rows.iter_mut().find(|row| &row.worker_id == id) { + Some(row) => row.activity = Some(progress.clone()), + None => rows.push(AgentRosterRow { + activity: Some(progress.clone()), + ..blank(id, name(id).unwrap_or_else(|| id.clone())) + }), + } + } + rows +} + pub(super) fn agents(app: &App) -> Vec> { - app.current_agent_roster() + live_rows(app) .iter() .map(|row| { let (state, label) = match row.state { diff --git a/crates/tui/src/tui/pet_watch/mod.rs b/crates/tui/src/tui/pet_watch/mod.rs index 89634846b1..0c43d57ffb 100644 --- a/crates/tui/src/tui/pet_watch/mod.rs +++ b/crates/tui/src/tui/pet_watch/mod.rs @@ -457,10 +457,6 @@ pub fn tick(app: &mut App, now: Instant) { if visible && app.pet_watch.avatars.refresh(&app.workspace, now) { app.needs_redraw = true; } - let waiting = matches!( - ShellPhase::from_app(app), - ShellPhase::Waiting | ShellPhase::Approval - ); let sound_allowed = visible && app.onboarding == crate::tui::app::OnboardingState::None && !app.notification_settings.quiet @@ -513,41 +509,47 @@ pub fn tick(app: &mut App, now: Instant) { .last_tick .is_none_or(|t| now.saturating_duration_since(t) >= Duration::from_millis(30)) { - let a = state.area.unwrap_or(Rect::new(0, 0, 40, 8)); - let cell = crossterm::terminal::window_size() - .ok() - .filter(|s| s.columns > 0 && s.rows > 0 && s.width > 0 && s.height > 0) - .map(|s| { - ( - f64::from(s.width) / f64::from(s.columns), - f64::from(s.height) / f64::from(s.rows), - ) - }) - .unwrap_or((8.0, 16.0)); - let next = live::View { - locale: app.ui_locale.tag().into(), - width: a.width.clamp(1, 512), - height: a.height.saturating_sub(1).clamp(1, 256), - cell_width: cell.0, - cell_height: cell.1, - motion, - pixels: !full::canonical(state) - && matches!(state.avatars.key.as_str(), "" | "whale") - && crate::tui::mark::kitty_graphics_supported() - && app.synchronized_output_enabled - && std::env::var("CODEWHALE_PET_GRAPHICS").as_deref() != Ok("braille"), - visible, - waiting, - sound: state.sound_requested && sound_allowed, - }; - if let Some(worker) = &state.worker - && let Ok(mut view) = worker.view.lock() - { - *view = next; - } state.last_tick = Some(now); + let state = &app.pet_watch; + if let Some(worker) = &state.worker { + let waiting = matches!( + ShellPhase::from_app(app), + ShellPhase::Waiting | ShellPhase::Approval + ); + let a = state.area.unwrap_or(Rect::new(0, 0, 40, 8)); + let cell = crossterm::terminal::window_size() + .ok() + .filter(|s| s.columns > 0 && s.rows > 0 && s.width > 0 && s.height > 0) + .map(|s| { + ( + f64::from(s.width) / f64::from(s.columns), + f64::from(s.height) / f64::from(s.rows), + ) + }) + .unwrap_or((8.0, 16.0)); + let next = live::View { + locale: app.ui_locale.tag().into(), + width: a.width.clamp(1, 512), + height: a.height.saturating_sub(1).clamp(1, 256), + cell_width: cell.0, + cell_height: cell.1, + motion, + pixels: !full::canonical(state) + && matches!(state.avatars.key.as_str(), "" | "whale") + && crate::tui::mark::kitty_graphics_supported() + && app.synchronized_output_enabled + && std::env::var("CODEWHALE_PET_GRAPHICS").as_deref() != Ok("braille"), + visible, + waiting, + sound: state.sound_requested && sound_allowed, + }; + if let Ok(mut view) = worker.view.lock() { + *view = next; + } + } } - let notices: Vec<_> = state + let notices: Vec<_> = app + .pet_watch .worker .as_ref() .map(|w| w.notices.try_iter().take(16).collect()) diff --git a/crates/tui/src/tui/phase_strip.rs b/crates/tui/src/tui/phase_strip.rs index 522e25830a..3c30387ca6 100644 --- a/crates/tui/src/tui/phase_strip.rs +++ b/crates/tui/src/tui/phase_strip.rs @@ -54,7 +54,7 @@ pub(crate) fn route_identity_fields( // A route that cannot prove its effective tier states no effort field // rather than `high→effective unavailable` (#5950): a placeholder that // can never resolve is noise, not a reading. First-party routes keep - // their tier, `auto: tier` and `req→eff` labels. + // their tier and `req→eff` labels. // Labeled, so a bare "max" never sits on the row unexplained (mark 8). let effort = app .provable_reasoning_effort_label() @@ -1099,7 +1099,9 @@ pub(crate) fn tideline_footer_from_app(app: &mut App, width: u16) -> TidelineFoo // MCP or plugin boot chip, else the remote-control state when it is on. // Clause-shed against half the row — the posture facts own the other // half. - let notice_budget = (usize::from(width) / 2).max(8); + let notice_budget = (usize::from(width) / 2) + .max(8) + .min(usize::from(width).saturating_sub(permission_chip.0.width() + 5)); let right = selected_notice(app.active_status_toast(phase), &phase_label) .map(|(text, ink, _urgent)| { ( @@ -1128,9 +1130,14 @@ pub(crate) fn tideline_footer_from_app(app: &mut App, width: u16) -> TidelineFoo }) .and_then(|(text, ink)| fit_notice(&text, notice_budget).map(|fitted| (fitted, ink))) .or_else(|| { + let ink = if app.remote_control.status() == crate::remote_control::Status::Failed { + ChromeInk::Failure + } else { + ChromeInk::Info + }; app.remote_control .status_word() - .map(|word| (format!("/rc {word}"), ChromeInk::Info)) + .map(|word| (format!("/rc {word}"), ink)) }); let (turn_clock, session_clock) = working_clock(app, phase, &phase_label); diff --git a/crates/tui/src/tui/provider_picker.rs b/crates/tui/src/tui/provider_picker.rs index b8c9bb10a0..92648788b8 100644 --- a/crates/tui/src/tui/provider_picker.rs +++ b/crates/tui/src/tui/provider_picker.rs @@ -3660,8 +3660,8 @@ impl ProviderPickerView { inner, buf, &[ - ActionHint::new("Enter", "continue"), - ActionHint::new("Esc", "back"), + ActionHint::new("Enter", self.tr(MessageId::SetupActionContinue)), + ActionHint::new("Esc", self.tr(MessageId::SetupActionBack)), ], ) }; @@ -3760,10 +3760,13 @@ impl ProviderPickerView { }; if let Some(ref error) = self.key_entry_error { - hint_lines.push(Line::from(Span::styled( - error.clone(), - Style::default().fg(palette::STATUS_ERROR), - ))); + hint_lines.insert( + 0, + Line::from(Span::styled( + error.clone(), + Style::default().fg(palette::STATUS_ERROR), + )), + ); } // `Line` count is not rendered row count: long environment-variable @@ -4031,8 +4034,8 @@ impl ProviderPickerView { buf, &[ ActionHint::new("↑↓", "move"), - ActionHint::new("Enter", "continue"), - ActionHint::new("Esc", "back"), + ActionHint::new("Enter", self.tr(MessageId::SetupActionContinue)), + ActionHint::new("Esc", self.tr(MessageId::SetupActionBack)), ], ); @@ -4148,8 +4151,8 @@ impl ProviderPickerView { buf, &[ ActionHint::new("↑↓", "choose"), - ActionHint::new("Enter", "continue"), - ActionHint::new("Esc", "back"), + ActionHint::new("Enter", self.tr(MessageId::SetupActionContinue)), + ActionHint::new("Esc", self.tr(MessageId::SetupActionBack)), ], ); self.render_setup_choices( @@ -4187,8 +4190,8 @@ impl ProviderPickerView { buf, &[ ActionHint::new("↑↓", "choose"), - ActionHint::new("Enter", "continue"), - ActionHint::new("Esc", "back"), + ActionHint::new("Enter", self.tr(MessageId::SetupActionContinue)), + ActionHint::new("Esc", self.tr(MessageId::SetupActionBack)), ], ); // Keep the actual endpoint with each route; choosing only stages diff --git a/crates/tui/src/tui/selection.rs b/crates/tui/src/tui/selection.rs index dea1c6707b..069a425486 100644 --- a/crates/tui/src/tui/selection.rs +++ b/crates/tui/src/tui/selection.rs @@ -17,6 +17,7 @@ pub struct TranscriptSelection { pub anchor: Option, pub head: Option, pub dragging: bool, + pub(crate) owner: Option, } /// Drag-past-edge auto-scroll state. While the user holds the left button @@ -39,6 +40,7 @@ impl TranscriptSelection { self.anchor = None; self.head = None; self.dragging = false; + self.owner = None; } /// Whether a full selection is active. diff --git a/crates/tui/src/tui/setup/mod.rs b/crates/tui/src/tui/setup/mod.rs index 19e8d2d945..a5de68c911 100644 --- a/crates/tui/src/tui/setup/mod.rs +++ b/crates/tui/src/tui/setup/mod.rs @@ -23,7 +23,7 @@ use crate::config::{Config, has_api_key}; use crate::prompts::{ BASE_PROMPT_OVERRIDE_OPT_IN_ENV, CONSTITUTION_OVERRIDE_FILE, base_prompt_override_opt_in, }; -use crate::tui::app::App; +use crate::tui::app::{App, AppModeUi}; use crate::tui::onboarding; use crate::tui::views::{ ActionHint, ModalKind, ModalView, ViewAction, ViewEvent, render_modal_footer, @@ -507,7 +507,7 @@ impl SetupRuntimeFacts { provider_ready, provider_status, provider_result, - work_intent: app.mode.display_name().to_string(), + work_intent: app.mode.display_name_localized(app.ui_locale).into_owned(), approval: app .approval_mode .permission_chip_label() @@ -547,17 +547,12 @@ impl SetupRuntimeFacts { remote_command_provider: remote.command_provider, remote_result: remote.result, remote_control_result: { - let status = app.remote_control.status_line(); - let message = if status.starts_with("Remote control: connected") { - MessageId::SetupRemoteStatusReady - } else if status.starts_with("Remote control: connecting") - || status.starts_with("Remote control: stopping") - { - MessageId::SetupStatusInProgress - } else if status.starts_with("Remote control: disconnected") { - MessageId::SetupRemoteStatusNeedsAction - } else { - MessageId::SetupRemoteStatusDisabled + use crate::remote_control::Status; + let message = match app.remote_control.status() { + Status::Connected => MessageId::SetupRemoteStatusReady, + Status::Connecting | Status::Stopping => MessageId::SetupStatusInProgress, + Status::Failed => MessageId::SetupRemoteStatusNeedsAction, + Status::Off => MessageId::SetupRemoteStatusDisabled, }; tr(app.ui_locale, message).into_owned() }, @@ -835,63 +830,63 @@ impl GuidedConstitutionDraft { let own_words = match locale { Locale::Ja => format!( "\nユーザー自由原則:{}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::ZhHans => format!( "\n用户自定义准则:{}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::ZhHant => format!( "\n使用者自由原則:{}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::PtBr => format!( "\nPrincípio livre do usuário: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Es419 => format!( "\nPrincipio libre del usuario: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Vi => format!( "\nNguyên tắc tự do của người dùng: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Ko => format!( "\n사용자 자유 원칙: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Ca => format!( "\nPrincipi lliure de l'usuari: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::De => format!( "\nFreitext-Prinzip des Nutzers: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Fr => format!( "\nPrincipe en texte libre de l'utilisateur : {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Id => format!( "\nPrinsip bebas pengguna: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Hi => format!( "\nउपयोगकर्ता मुक्त-पाठ सिद्धांत: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Ru => format!( "\nСвободный принцип пользователя: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), Locale::Uk => format!( "\nВільний принцип користувача: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), _ => format!( "\nUser freeform principle: {}", - bounded_freeform_note(note, MAX_NOTES_LEN) + bounded_freeform_note(note, FREEFORM_NOTE_MAX) ), }; notes.push_str(&own_words); @@ -2126,6 +2121,8 @@ fn authority_priority(locale: Locale) -> &'static str { } } +const FREEFORM_NOTE_MAX: usize = MAX_NOTES_LEN - 1_000; + fn bounded_freeform_note(input: &str, max_chars: usize) -> String { input .chars() @@ -2896,7 +2893,7 @@ impl SetupWizardView { fn append_freeform_note_text(&mut self, text: &str) { let mut next = self.freeform_note.clone(); next.push_str(text); - self.freeform_note = bounded_freeform_note(&next, MAX_NOTES_LEN); + self.freeform_note = bounded_freeform_note(&next, FREEFORM_NOTE_MAX); self.guided_preview_seen = false; self.model_draft = None; self.model_draft_label = None; @@ -3220,8 +3217,12 @@ impl ModalView for SetupWizardView { KeyCode::Char('k') if self.selected_step() == SetupStep::Constitution => { self.commit_keep_existing_constitution() } - KeyCode::Char('u') => self.commit_constitution(SetupCommitKind::BundledConstitution), - KeyCode::Char('d') => self.commit_constitution(SetupCommitKind::DeferredConstitution), + KeyCode::Char('u') if self.selected_step() == SetupStep::Constitution => { + self.commit_constitution(SetupCommitKind::BundledConstitution) + } + KeyCode::Char('d') if self.selected_step() == SetupStep::Constitution => { + self.commit_constitution(SetupCommitKind::DeferredConstitution) + } KeyCode::Enter if self.selected_step() == SetupStep::Constitution => { self.commit_constitution(SetupCommitKind::BundledConstitution) } @@ -3322,7 +3323,11 @@ impl ModalView for SetupWizardView { let spec = self.selected_spec(); let (title_text, question_text) = if self.progressive_guide { match self.selected_step() { - SetupStep::ProviderModel => ( + SetupStep::Verification if self.facts.provider_ready => ( + tr(self.locale, MessageId::OnboardReadyTitle).into_owned(), + tr(self.locale, MessageId::OnboardReadyLead).into_owned(), + ), + SetupStep::ProviderModel | SetupStep::Verification => ( tr(self.locale, MessageId::OnboardProviderTitle).into_owned(), tr(self.locale, MessageId::OnboardProviderBlurb).into_owned(), ), @@ -3334,10 +3339,6 @@ impl ModalView for SetupWizardView { "/rc".to_string(), tr(self.locale, MessageId::CmdRemoteControlDescription).into_owned(), ), - SetupStep::Verification => ( - tr(self.locale, MessageId::OnboardReadyTitle).into_owned(), - tr(self.locale, MessageId::OnboardReadyLead).into_owned(), - ), _ => ( tr(self.locale, spec.title_id()).into_owned(), tr(self.locale, spec.why_id()).into_owned(), @@ -3443,14 +3444,30 @@ impl SetupWizardView { details(), exit(), ], - SetupStep::Verification => vec![ - ActionHint::new( - "Enter", - tr(self.locale, MessageId::OnboardReadyStart).to_string(), - ), - details(), - exit(), - ], + SetupStep::Verification => { + let mut hints = vec![ + ActionHint::new( + "Enter", + tr(self.locale, MessageId::OnboardReadyStart).to_string(), + ), + ActionHint::new( + "C", + tr(self.locale, MessageId::SetupActionCustomize).to_string(), + ), + details(), + exit(), + ]; + if !self.facts.provider_ready { + hints.insert( + 0, + ActionHint::new( + "P", + tr(self.locale, MessageId::SetupActionProvider).to_string(), + ), + ); + } + hints + } _ => vec![exit()], }; let position = self @@ -4421,7 +4438,6 @@ fn constitution_ratification_text( Locale::Uk => "Структурована конституція порожня.".to_string(), _ => "The structured constitution is empty.".to_string(), }); - let layer_order = tr(locale, MessageId::SetupCheckpointLayerOrder); match locale { Locale::Ja => { @@ -4454,7 +4470,7 @@ fn constitution_ratification_text( すべての個別判断を裁くのではなく権限と境界を定め、セッションを越えて協働を継続させます。\ ただしこれは記憶ではありません。履歴ではなく原則を保持します。\n\n\ {rendered}\n\n\ - 権限の階層\n{layer_order}\nあなたの直接の指示は常にこの文書より優先されます。\n\n\ + 権限の階層\nあなたの直接の指示は常にこの文書より優先されます。\n\n\ これができないこと\n\ これは行動を導くものです。承認ポリシー、サンドボックス、Shell、ネットワーク、信頼、MCP 権限、\ 既定モード、公開、支出の権限を付与または変更することはできません。これらは実行時にあなたが管理します。\n\n\ @@ -4489,7 +4505,7 @@ fn constitution_ratification_text( 这是 Codewhale 与你协作时长期遵循的偏好和规则。内容应保持简短、便于执行,以持久原则为主,并可随时调整。\ 它界定协作方式与行为边界,而不是替你决定每一种情况;它让协作跨会话延续——但它不是记忆,只保留原则,不保留历史。\n\n\ {rendered}\n\n\ - 权限层级\n{layer_order}\n你的直接指令始终高于本文件。\n\n\ + 权限层级\n你的直接指令始终高于本文件。\n\n\ 它不能做什么\n\ 它只提供行为指导,不能授予或更改审批策略、沙箱、Shell、网络、信任、MCP 权限、默认模式、发布或支出权限——这些始终由你在运行时掌控。\n\n\ 精简核心与可选策略\n\ @@ -4522,7 +4538,7 @@ fn constitution_ratification_text( 這是 Codewhale 與你協作的長期準則。像優秀的憲法一樣:足夠簡短因而可用,由持久原則而非詳盡規則構成,並且可以隨你修訂。\ 它界定權力與邊界,而非裁決每個具體決定;它讓協作跨會話延續,但它不是記憶,它承載的是原則,而非歷史。\n\n\ {rendered}\n\n\ - 權限層級\n{layer_order}\n你的直接指令始終高於本文件。\n\n\ + 權限層級\n你的直接指令始終高於本文件。\n\n\ 它不能做什麼\n\ 它只提供行為指導,不能授予或更改審批策略、沙箱、Shell、網路、信任、MCP 權限、預設模式、發布或支出權限;這些始終由你在執行時掌控。\n\n\ 精簡核心與可選模組\n\ @@ -4560,7 +4576,7 @@ fn constitution_ratification_text( e pode ser emendada conforme você muda. Ela define poderes e limites em vez de decidir cada caso, \ e dá continuidade à colaboração entre sessões. Mas ela não é memória: carrega princípios, não histórico.\n\n\ {rendered}\n\n\ - HIERARQUIA DE AUTORIDADE\n{layer_order}\nSeus pedidos diretos sempre superam este documento.\n\n\ + HIERARQUIA DE AUTORIDADE\nSeus pedidos diretos sempre superam este documento.\n\n\ O QUE ISTO NÃO PODE FAZER\n\ Isto orienta comportamento. Não pode conceder nem alterar política de aprovação, sandbox, shell, rede, \ confiança, permissões MCP, modo padrão, publicação ou autoridade para gastos; isso continua sob seu controle em tempo de execução.\n\n\ @@ -4600,7 +4616,7 @@ fn constitution_ratification_text( y enmendable a medida que cambias. Define poderes y límites en vez de decidir cada caso, \ y da continuidad a la colaboración entre sesiones. Pero no es memoria: lleva principios, no historial.\n\n\ {rendered}\n\n\ - JERARQUÍA DE AUTORIDAD\n{layer_order}\nTus pedidos directos siempre superan este documento.\n\n\ + JERARQUÍA DE AUTORIDAD\nTus pedidos directos siempre superan este documento.\n\n\ LO QUE ESTO NO PUEDE HACER\n\ Orienta comportamiento. No puede conceder ni cambiar política de aprobación, sandbox, shell, red, \ confianza, permisos MCP, modo predeterminado, publicación o autoridad de gasto; eso sigue bajo tu control en tiempo de ejecución.\n\n\ @@ -4640,7 +4656,7 @@ fn constitution_ratification_text( và có thể sửa khi bạn thay đổi. Nó định khung quyền hạn và giới hạn thay vì quyết định từng trường hợp, \ đồng thời giữ sự liên tục giữa các phiên. Nhưng nó không phải bộ nhớ: nó mang nguyên tắc, không mang lịch sử.\n\n\ {rendered}\n\n\ - THỨ BẬC THẨM QUYỀN\n{layer_order}\nYêu cầu trực tiếp của bạn luôn cao hơn tài liệu này.\n\n\ + THỨ BẬC THẨM QUYỀN\nYêu cầu trực tiếp của bạn luôn cao hơn tài liệu này.\n\n\ ĐIỀU NÀY KHÔNG THỂ LÀM\n\ Nó hướng dẫn hành vi. Nó không thể cấp hoặc đổi chính sách phê duyệt, sandbox, shell, mạng, \ độ tin cậy, quyền MCP, chế độ mặc định, xuất bản hoặc quyền chi tiêu; những thứ đó vẫn do bạn kiểm soát lúc chạy.\n\n\ @@ -4680,7 +4696,7 @@ fn constitution_ratification_text( 이는 모든 개별 사례를 판단하는 대신 권한과 한계를 규정하며, 세션을 넘어 협업의 연속성을 부여합니다. \ 다만 이것은 기억이 아닙니다: 이력이 아니라 원칙을 담습니다.\n\n\ {rendered}\n\n\ - 권한 계층\n{layer_order}\n당신의 직접적인 요청은 언제나 이 문서보다 우선합니다.\n\n\ + 권한 계층\n당신의 직접적인 요청은 언제나 이 문서보다 우선합니다.\n\n\ 이것이 할 수 없는 일\n\ 이것은 행동을 안내할 뿐입니다. 승인 정책, 샌드박스, 셸, 네트워크, 신뢰, MCP 권한, 기본 모드, 게시, 지출 권한을 \ 부여하거나 바꿀 수 없습니다; 이는 여전히 런타임에서 당신이 직접 관리합니다.\n\n\ @@ -4720,7 +4736,7 @@ fn constitution_ratification_text( i esmenable a mesura que canvies. Defineix poders i límits en lloc de decidir cada cas, \ i dona continuïtat a la col·laboració entre sessions — però no és memòria: porta principis, no història.\n\n\ {rendered}\n\n\ - JERARQUIA D'AUTORITAT\n{layer_order}\nLes teves peticions directes sempre prevalen sobre aquest document.\n\n\ + JERARQUIA D'AUTORITAT\nLes teves peticions directes sempre prevalen sobre aquest document.\n\n\ EL QUE AIXÒ NO POT FER\n\ Orienta el comportament. No pot concedir ni canviar la política d'aprovació, sandbox, shell, xarxa, \ confiança, permisos MCP, mode per defecte, publicació o autoritat de despesa; això queda sota el teu control en temps d'execució.\n\n\ @@ -4760,7 +4776,7 @@ fn constitution_ratification_text( und lässt sich ändern, wenn du dich änderst. Sie rahmt Befugnisse und Grenzen, statt jeden Einzelfall zu entscheiden, \ und gibt deiner Zusammenarbeit Kontinuität über Sitzungen hinweg — aber sie ist kein Gedächtnis: Sie trägt Prinzipien, nicht Geschichte.\n\n\ {rendered}\n\n\ - HIERARCHIE DER AUTORITÄT\n{layer_order}\nDeine direkten Anweisungen stehen immer über diesem Dokument.\n\n\ + HIERARCHIE DER AUTORITÄT\nDeine direkten Anweisungen stehen immer über diesem Dokument.\n\n\ WAS DIES NICHT KANN\n\ Sie leitet Verhalten. Sie kann keine Freigaberichtlinie, Sandbox, Shell, Netzwerk, \ Vertrauen, MCP-Berechtigungen, Standardmodus, Veröffentlichung oder Ausgabenbefugnis gewähren oder ändern — die bleiben zur Laufzeit in deiner Hand.\n\n\ @@ -4800,7 +4816,7 @@ fn constitution_ratification_text( et amendable à mesure que vous changez. Elle encadre les pouvoirs et les limites plutôt que de trancher chaque cas, \ et donne à votre collaboration une continuité entre les sessions — mais elle n'est pas une mémoire : elle porte des principes, pas un historique.\n\n\ {rendered}\n\n\ - HIÉRARCHIE D'AUTORITÉ\n{layer_order}\nVos demandes directes priment toujours sur ce document.\n\n\ + HIÉRARCHIE D'AUTORITÉ\nVos demandes directes priment toujours sur ce document.\n\n\ CE QU'ELLE NE PEUT PAS FAIRE\n\ Elle guide le comportement. Elle ne peut ni accorder ni modifier la politique d'approbation, le sandbox, le shell, le réseau, \ la confiance, les permissions MCP, le mode par défaut, la publication ou le pouvoir de dépense — ceux-ci restent entre vos mains à l'exécution.\n\n\ @@ -4840,7 +4856,7 @@ fn constitution_ratification_text( dan dapat diamendemen seiring Anda berubah. Ia membingkai wewenang dan batasan alih-alih memutuskan setiap kasus, \ dan memberi kolaborasi Anda kesinambungan lintas sesi — tetapi ia bukan memori: ia membawa prinsip, bukan riwayat.\n\n\ {rendered}\n\n\ - HIERARKI OTORITAS\n{layer_order}\nPermintaan langsung Anda selalu mengungguli dokumen ini.\n\n\ + HIERARKI OTORITAS\nPermintaan langsung Anda selalu mengungguli dokumen ini.\n\n\ APA YANG TIDAK BISA DILAKUKANNYA\n\ Ia memandu perilaku. Ia tidak dapat memberi atau mengubah kebijakan persetujuan, sandbox, shell, jaringan, \ kepercayaan, izin MCP, mode default, publikasi, atau wewenang belanja — semua itu tetap di tangan Anda saat runtime.\n\n\ @@ -4878,7 +4894,7 @@ fn constitution_ratification_text( और आपके बदलने के साथ संशोधनीय है। यह हर मामले का फ़ैसला करने के बजाय शक्तियों और सीमाओं का ढाँचा देता है, \ और आपके सहयोग को सत्रों के पार निरंतरता देता है — लेकिन यह मेमोरी नहीं है: यह इतिहास नहीं, सिद्धांत रखता है।\n\n\ {rendered}\n\n\ - अधिकार पदानुक्रम\n{layer_order}\nआपके प्रत्यक्ष अनुरोध हमेशा इस दस्तावेज़ से ऊपर हैं।\n\n\ + अधिकार पदानुक्रम\nआपके प्रत्यक्ष अनुरोध हमेशा इस दस्तावेज़ से ऊपर हैं।\n\n\ यह क्या नहीं कर सकता\n\ यह व्यवहार का मार्गदर्शन करता है। यह अनुमति नीति, सैंडबॉक्स, शेल, नेटवर्क, \ ट्रस्ट, MCP अनुमतियाँ, डिफ़ॉल्ट मोड, प्रकाशन या खर्च का अधिकार प्रदान या परिवर्तित नहीं कर सकता — वे रनटाइम पर आपके हाथ में रहते हैं।\n\n\ @@ -4918,7 +4934,7 @@ fn constitution_ratification_text( и может изменяться вместе с вами. Она очерчивает полномочия и границы, а не решает каждый случай, \ и придаёт вашему сотрудничеству непрерывность между сессиями — но она не память: она хранит принципы, а не историю.\n\n\ {rendered}\n\n\ - ИЕРАРХИЯ ПОЛНОМОЧИЙ\n{layer_order}\nВаши прямые указания всегда важнее этого документа.\n\n\ + ИЕРАРХИЯ ПОЛНОМОЧИЙ\nВаши прямые указания всегда важнее этого документа.\n\n\ ЧЕГО ОНА НЕ МОЖЕТ\n\ Она направляет поведение. Она не может предоставить или изменить политику одобрения, sandbox, shell, сеть, \ доверие, разрешения MCP, режим по умолчанию, публикацию или право тратить — они остаются в ваших руках во время выполнения.\n\n\ @@ -4958,7 +4974,7 @@ fn constitution_ratification_text( і може змінюватися разом із вами. Вона окреслює повноваження та межі, а не вирішує кожен випадок, \ і надає вашій співпраці неперервність між сесіями — але вона не пам'ять: вона зберігає принципи, а не історію.\n\n\ {rendered}\n\n\ - ІЄРАРХІЯ ПОВНОВАЖЕНЬ\n{layer_order}\nВаші прямі вказівки завжди важливіші за цей документ.\n\n\ + ІЄРАРХІЯ ПОВНОВАЖЕНЬ\nВаші прямі вказівки завжди важливіші за цей документ.\n\n\ ЧОГО ВОНА НЕ МОЖЕ\n\ Вона спрямовує поведінку. Вона не може надати або змінити політику схвалення, sandbox, shell, мережу, \ довіру, дозволи MCP, режим за замовчуванням, публікацію чи право витрачати — вони залишаються у ваших руках під час виконання.\n\n\ @@ -5001,7 +5017,7 @@ fn constitution_ratification_text( continuity across sessions — but it is not memory: it carries principles, \ not history.\n\n\ {rendered}\n\n\ - HIERARCHY OF AUTHORITY\n{layer_order}\nYour direct requests always outrank this document.\n\n\ + HIERARCHY OF AUTHORITY\nYour direct requests always outrank this document.\n\n\ WHAT THIS CANNOT DO\n\ It guides behavior. It cannot grant or change approval policy, sandbox, shell, \ network, trust, MCP permissions, default mode, publishing, or spending \ diff --git a/crates/tui/src/tui/shell_job_routing.rs b/crates/tui/src/tui/shell_job_routing.rs index 64d2c28146..babafcf194 100644 --- a/crates/tui/src/tui/shell_job_routing.rs +++ b/crates/tui/src/tui/shell_job_routing.rs @@ -1,8 +1,16 @@ //! Background shell job-center helpers for slash commands and pagers. +//! +//! Known limitations: the Bash Job pager (opened from `/jobs`, Alt+V or a +//! work-dock shell row) follows a running job by re-reading it on the event +//! loop's 2.5 s refresh (a bounded read that never consumes the model's +//! output cursor), so new output lands up to 2.5 s late. Shells run by +//! delegated agents show in `/jobs` and the dock with their Owner, not in the +//! agent's detail. Named PTY sessions (`tools/terminal_session.rs`) are not +//! listed here or in `/jobs`; they live in the terminal dock (#6912). use crate::tools::shell::{ShellJobDetail, ShellJobSnapshot, ShellResult, ShellStatus}; use crate::tui::app::App; -use crate::tui::history::{HistoryCell, ToolCell, ToolStatus}; +use crate::tui::history::{HistoryCell, ToolCell}; use crate::tui::pager::PagerView; use crate::tui::views::{CommandPaletteAction, ViewEvent}; use codewhale_localization::MessageId; @@ -82,6 +90,16 @@ pub(super) fn format_shell_poll(result: &ShellResult) -> String { ), String::new(), ]; + if result.status == ShellStatus::Killed { + lines.push( + crate::tools::shell_output::kill_outcome_note(&format!( + "{}{}", + result.stdout, result.stderr + )) + .to_string(), + ); + lines.push(String::new()); + } if result.stdout.is_empty() && result.stderr.is_empty() { lines.push("(no new output)".to_string()); } else { @@ -139,15 +157,6 @@ pub(crate) fn shell_job_for_cell(app: &App, cell_index: usize) -> Option Option { - (0..app.virtual_cell_count()).rev().find(|&index| { - matches!( - app.cell_at_virtual_index(index), - Some(HistoryCell::Tool(ToolCell::Exec(exec))) if exec.status == ToolStatus::Running - ) - }) -} - pub(crate) fn open_shell_job_pager(app: &mut App, detail: &ShellJobDetail) { let width = app .viewport @@ -164,6 +173,7 @@ pub(crate) fn open_shell_job_pager(app: &mut App, detail: &ShellJobDetail) { ) .with_copy_text(body); if live { + pager = pager.with_live_shell_job(detail.snapshot.id.clone()); pager = pager.with_destructive_action( 's', app.tr(MessageId::SidebarStopControl), @@ -178,11 +188,55 @@ pub(crate) fn open_shell_job_pager(app: &mut App, detail: &ShellJobDetail) { app.view_stack.push(pager); } +pub(crate) fn refresh_live_shell_job_pager(app: &mut App) -> bool { + let Some(job_id) = app + .view_stack + .top_pager_mut() + .and_then(|pager| pager.live_shell_job().map(str::to_owned)) + else { + return false; + }; + let Some(shell_manager) = app.runtime_services.shell_manager.clone() else { + return false; + }; + let session = app.current_session_id.clone().unwrap_or_default(); + let detail = { + let Ok(mut manager) = shell_manager.try_lock() else { + return false; + }; + manager.inspect_job_for_session(&session, &job_id).ok() + }; + let Some(pager) = app.view_stack.top_pager_mut() else { + return false; + }; + let Some(detail) = detail else { + pager.end_live_shell_job(); + return true; + }; + let changed = pager.replace_live_text(&format_shell_job_detail(&detail)); + if detail.snapshot.status != ShellStatus::Running { + pager.end_live_shell_job(); + return true; + } + changed +} + +fn detail_status_label(job: &ShellJobSnapshot) -> String { + let quiet = + u64::try_from(crate::tools::shell::QUIET_NO_OUTPUT_AFTER.as_millis()).unwrap_or(u64::MAX); + match job.elapsed_since_output_ms { + Some(ms) if job.status == ShellStatus::Running && !job.stale && ms >= quiet => { + crate::tui::history::stale_shell_status_label(ms) + } + _ => status_label(&job.status, job.stale).to_string(), + } +} + pub(crate) fn format_shell_job_detail(detail: &ShellJobDetail) -> String { let job = &detail.snapshot; let mut lines = vec![ format!("Job: {}", job.id), - format!("Status: {}", status_label(&job.status, job.stale)), + format!("Status: {}", detail_status_label(job)), format!("Command: {}", job.command), format!("Cwd: {}", crate::utils::display_path(&job.cwd)), ]; @@ -245,14 +299,13 @@ mod tests { use super::*; use std::path::PathBuf; - #[test] - fn list_shows_controls_and_stale_state() { - let jobs = vec![ShellJobSnapshot { + fn snapshot(status: ShellStatus, stale: bool) -> ShellJobSnapshot { + ShellJobSnapshot { id: "shell_dead".to_string(), job_id: "shell_dead".to_string(), command: "cargo test".to_string(), cwd: PathBuf::from("/tmp/repo"), - status: ShellStatus::Killed, + status, exit_code: None, elapsed_ms: 0, stdout_tail: String::new(), @@ -260,7 +313,7 @@ mod tests { stdout_len: 0, stderr_len: 8, stdin_available: false, - stale: true, + stale, elapsed_since_output_ms: None, linked_task_id: Some("task_1".to_string()), owner_agent_id: None, @@ -270,7 +323,26 @@ mod tests { owner_session_id: "session-test".to_string(), background: true, finished_at: Some(chrono::Utc::now()), - }]; + } + } + + #[test] + fn silent_running_job_detail_reads_quiet_not_stale() { + let mut job = snapshot(ShellStatus::Running, false); + job.elapsed_since_output_ms = Some(125_000); + let body = format_shell_job_detail(&ShellJobDetail { + snapshot: job, + stdout: String::new(), + stderr: String::new(), + }); + assert!(body.contains("Status: running · no output for"), "{body}"); + assert!(body.contains("(no output yet)"), "{body}"); + assert!(!body.contains("stale"), "{body}"); + } + + #[test] + fn list_shows_controls_and_stale_state() { + let jobs = vec![snapshot(ShellStatus::Killed, true)]; let formatted = format_shell_job_list(&jobs); assert!(formatted.contains("Bash jobs (1)")); assert!(!formatted.contains("Background commands")); diff --git a/crates/tui/src/tui/subagent_routing.rs b/crates/tui/src/tui/subagent_routing.rs index e8888e2a6a..27693a16a3 100644 --- a/crates/tui/src/tui/subagent_routing.rs +++ b/crates/tui/src/tui/subagent_routing.rs @@ -182,7 +182,7 @@ pub(super) fn apply_subagent_terminal_projection( true } -fn worker_status_for_terminal_projection(status: &SubAgentStatus) -> AgentWorkerStatus { +pub(crate) fn worker_status_for_terminal_projection(status: &SubAgentStatus) -> AgentWorkerStatus { match status { SubAgentStatus::Running => AgentWorkerStatus::Running, SubAgentStatus::Completed => AgentWorkerStatus::Completed, diff --git a/crates/tui/src/tui/tool_routing.rs b/crates/tui/src/tui/tool_routing.rs index a94d33eb76..0139e1e702 100644 --- a/crates/tui/src/tui/tool_routing.rs +++ b/crates/tui/src/tui/tool_routing.rs @@ -57,6 +57,7 @@ pub(super) fn handle_tool_call_started( ExploringEntry { label, status: ToolStatus::Running, + error: None, }, ) .map_or(0, |(_, inner)| inner); @@ -714,16 +715,18 @@ pub(super) fn handle_tool_call_complete( // Preserve the execution/audit name while recovering the action-qualified // semantic name from the registered call input. Active entries and // already-flushed history use separate detail stores. - let semantic_name = app - .active_tool_details - .get(id) - .or_else(|| { - app.tool_cells - .get(id) - .and_then(|cell_index| app.tool_details_by_cell.get(cell_index)) - }) + let detail = app.active_tool_details.get(id).or_else(|| { + app.tool_cells + .get(id) + .and_then(|cell_index| app.tool_details_by_cell.get(cell_index)) + }); + let semantic_name = detail .map_or(name, |detail| canonical_action_alias(name, &detail.input)) .to_string(); + let explicit_background = detail.is_some_and(|detail| { + exec_is_background(&detail.input) + || detail.input.get("tty").and_then(serde_json::Value::as_bool) == Some(true) + }); // Roll any child-LLM token usage the tool reports into the // session-cost counter. Runs unconditionally so future tools that @@ -769,6 +772,14 @@ pub(super) fn handle_tool_call_complete( && let Some(entry) = cell.entries.get_mut(entry_index) { entry.status = tool_status_from_result(result); + entry.error = if entry.status == ToolStatus::Failed { + match result { + Ok(tool_result) => visible_tool_output(&tool_result.content), + Err(err) => Some(err.to_string()), + } + } else { + None + }; app.mark_history_updated(); // Mutating the in-flight exploring cell needs an active-cell // revision bump so the transcript cache invalidates the synthetic @@ -809,6 +820,7 @@ pub(super) fn handle_tool_call_complete( }) .flatten(); let mut workflow_panel_output: Option = None; + let mut moved_to_jobs = false; if let Some(cell) = app.cell_at_virtual_index_mut(cell_index) { match cell { @@ -874,11 +886,8 @@ pub(super) fn handle_tool_call_complete( .as_deref() .map(super::history::summarize_tool_output); exec.live_output = None; - } else if status == ToolStatus::Running - && exec.interaction.is_none() - && !tool_result.content.is_empty() - { - exec.live_output = Some(tool_result.content.clone()); + } else if status == ToolStatus::Running && exec.interaction.is_none() { + moved_to_jobs = !explicit_background; } } else if let Err(err) = result.as_ref() && exec.interaction.is_none() @@ -999,6 +1008,12 @@ pub(super) fn handle_tool_call_complete( if let Some(output) = workflow_panel_output.as_deref() { apply_workflow_output_to_panel(app, output); } + if moved_to_jobs { + let notice = app + .tr(codewhale_localization::MessageId::ShellWaitReleased) + .replace("{jobs}", "/jobs"); + app.push_status_toast(notice, crate::tui::app::StatusToastLevel::Info, Some(6_000)); + } // If the mutated cell lived inside the active group, bump the active-cell // revision so the transcript cache re-renders the synthetic tail row. diff --git a/crates/tui/src/tui/ui/activity_detail.rs b/crates/tui/src/tui/ui/activity_detail.rs index 9e09849e5f..bb7285d6d9 100644 --- a/crates/tui/src/tui/ui/activity_detail.rs +++ b/crates/tui/src/tui/ui/activity_detail.rs @@ -10,7 +10,7 @@ use crate::snapshot::SnapshotRepo; use crate::tui::app::App; use crate::tui::footer_ui::one_line_summary; -use crate::tui::history::{HistoryCell, ToolCell, ToolStatus}; +use crate::tui::history::{HistoryCell, ToolCell, ToolStatus, tool_status_label}; use crate::tui::pager::{PagerPage, PagerView}; use crate::tui::ui_text::{ history_cell_to_clipboard_text, history_cell_to_text, truncate_line_to_width, @@ -18,6 +18,9 @@ use crate::tui::ui_text::{ use codewhale_localization::{MessageId, tr}; fn selected_transcript_cell_index(app: &App) -> Option { + if let Some(owner) = app.selection_owner_cell() { + return Some(owner); + } app.viewport .transcript_selection .ordered_endpoints() @@ -250,16 +253,6 @@ fn tool_duration_for_activity(tool: &ToolCell) -> Option { } } -fn activity_status_label(status: ToolStatus) -> &'static str { - match status { - ToolStatus::Running => "running", - ToolStatus::Success => "done", - ToolStatus::Hydrated => "tool loaded - retry required", - ToolStatus::Warning => "issue", - ToolStatus::Failed => "failed", - } -} - /// Empty-state hint shown when the selection has no raw leaf detail to open. /// `v` / `Alt+V` only ever surface the raw detail of the ONE selected /// tool/card/leaf, so when there is nothing leaf-level to show we point the @@ -275,20 +268,7 @@ const RAW_DETAIL_PAGER_INTRO: &str = "Raw detail for the selected item — press Ctrl+Alt+O for the whole-turn overview."; pub(super) fn open_tool_details_pager(app: &mut App) -> bool { - let target_cell = if app - .viewport - .transcript_selection - .ordered_endpoints() - .is_some() - { - detail_target_cell_index(app) - } else { - crate::tui::shell_job_routing::newest_running_shell_cell(app) - .filter(|&idx| crate::tui::shell_job_routing::shell_job_for_cell(app, idx).is_some()) - .or_else(|| detail_target_cell_index(app)) - }; - - let Some(cell_index) = target_cell else { + let Some(cell_index) = detail_target_cell_index(app) else { app.status_message = Some(NO_RAW_DETAIL_HINT.to_string()); return false; }; @@ -595,6 +575,9 @@ fn turn_answer_payload(app: &App, start: usize, end: usize, width: u16) -> Optio } pub(super) fn detail_target_cell_index(app: &App) -> Option { + if let Some(owner) = app.selection_owner_cell() { + return Some(owner); + } if let Some((start, _)) = app.viewport.transcript_selection.ordered_endpoints() { return app .viewport @@ -1197,7 +1180,7 @@ fn turn_timeline_lines(app: &App, start: usize, end: usize) -> Vec { let (kind, summary) = timeline_tool_summary(app, idx, tool); let duration = tool_duration_for_activity(tool) .map(codewhale_command_contract::elapsed::format_elapsed_ms); - let status = tool.status().map(activity_status_label); + let status = tool.status().map(tool_status_label); let actions = timeline_cell_actions(app, idx, cell); rows.push(timeline_row( kind, @@ -1451,7 +1434,7 @@ fn turn_files_changed(app: &App, start: usize, end: usize) -> Vec { lines.push(format!( "• {} — {}", truncate_line_to_width(&patch.path, 60), - activity_status_label(patch.status) + tool_status_label(patch.status) )); } _ => {} @@ -1520,7 +1503,7 @@ fn turn_verifier_lines(app: &App, start: usize, end: usize) -> Vec { lines.push(format!( "• {} — {}", truncate_line_to_width(&exec.command, 56), - activity_status_label(exec.status) + tool_status_label(exec.status) )); } ToolCell::Review(review) => { @@ -1530,10 +1513,7 @@ fn turn_verifier_lines(app: &App, start: usize, end: usize) -> Vec { } else { format!("review {target}") }; - lines.push(format!( - "• {target} — {}", - activity_status_label(review.status) - )); + lines.push(format!("• {target} — {}", tool_status_label(review.status))); } _ => {} } diff --git a/crates/tui/src/tui/ui/apply.rs b/crates/tui/src/tui/ui/apply.rs index 45d2670ba2..8f6b747755 100644 --- a/crates/tui/src/tui/ui/apply.rs +++ b/crates/tui/src/tui/ui/apply.rs @@ -688,9 +688,11 @@ pub(crate) fn apply_goal_snapshot_to_app(app: &mut App, snapshot: &GoalSnapshot) // A fresh reported-progress receipt reads like the model's own status // line: percent with a bar, then the optional now/next lines it wrote. // Paused/complete goals keep their last report silent — the lifecycle - // receipt already spoke. + // receipt already spoke — except a yield, whose progress is the stage + // report the user is handed back with. if progress_changed - && verdict == GoalStatus::Active + && (verdict == GoalStatus::Active + || snapshot.pause_reason == Some(crate::tools::goal::GoalPauseReason::Yielded)) && let Some(progress) = snapshot.progress.as_ref() { let mut content = app @@ -4435,7 +4437,7 @@ pub(crate) fn apply_loaded_session_with_goal( { app.extend_history(std::iter::once(HistoryCell::Error { message: outcome.error.clone(), - severity: crate::error_taxonomy::ErrorSeverity::Warning, + severity: crate::error_taxonomy::ErrorSeverity::Error, })); } }; diff --git a/crates/tui/src/tui/ui/event_loop.rs b/crates/tui/src/tui/ui/event_loop.rs index 89023504be..517de23b63 100644 --- a/crates/tui/src/tui/ui/event_loop.rs +++ b/crates/tui/src/tui/ui/event_loop.rs @@ -64,8 +64,11 @@ pub(super) fn apply_engine_session_projection( { surface_goal_persistence_failure(app, &error); } - app.context_token_cache.borrow_mut().clear(); - app.set_api_messages(messages); + let unchanged = app.set_api_messages(messages); + app.context_token_cache + .get_mut() + .message_tokens + .truncate(unchanged); // #6190: the projection is the engine's own record, so it is where a // steer's acceptance becomes observable — and the only place the steer's // real message index is known. Promote before anything else reads the @@ -466,6 +469,7 @@ pub(super) fn handle_transcript_space(app: &mut App) -> bool { app.viewport.transcript_selection.clear(); app.viewport.transcript_selection.anchor = Some(point); app.viewport.transcript_selection.head = Some(point); + app.viewport.transcript_selection.owner = Some(owner); } app.mark_history_updated(); true @@ -1549,6 +1553,19 @@ pub(super) fn present_turn_failure( error: Option<&str>, ) { let failed = matches!(status, crate::core::events::TurnOutcomeStatus::Failed); + if failed + && app.turn_error_posted + && let Some(notice) = app.turn_error_notice.clone() + && let Some(index) = (0..app.virtual_cell_count()).rev().find(|&index| { + matches!( + app.cell_at_virtual_index(index), + Some(HistoryCell::Error { message, .. }) if *message == notice + ) + }) + && let Some(HistoryCell::Error { severity, .. }) = app.cell_at_virtual_index_mut(index) + { + *severity = crate::error_taxonomy::ErrorSeverity::Error; + } // What the transcript shows for this turn's failure: the error cell an // earlier `Event::Error` already posted, or the notice added here. let shown = if app.turn_error_posted { @@ -1558,7 +1575,7 @@ pub(super) fn present_turn_failure( if failed { app.add_message(HistoryCell::Error { message: notice.clone(), - severity: crate::error_taxonomy::ErrorSeverity::Warning, + severity: crate::error_taxonomy::ErrorSeverity::Error, }); } app.set_sticky_status(notice.clone(), StatusToastLevel::Error, None); @@ -2009,7 +2026,7 @@ pub(crate) async fn run_event_loop( if let Err(err) = completion { tracing::warn!(error = %err, "background terminal clipboard write failed"); app.push_status_toast( - format!("Clipboard copy failed: {err}"), + crate::tui::mouse_ui::copy_failed_receipt(app, &err), StatusToastLevel::Error, None, ); @@ -2228,6 +2245,9 @@ pub(crate) async fn run_event_loop( if refresh_shell_exec_live_output(app) { app.needs_redraw = true; } + if crate::tui::shell_job_routing::refresh_live_shell_job_pager(app) { + app.needs_redraw = true; + } if app .runtime_services .work @@ -2891,7 +2911,7 @@ pub(crate) async fn run_event_loop( // to interrupt a long-running turn (#1367). Only // surface when the status_message slot is empty so // we don't trample over a real transient message - // (e.g. "/queue saved", "Selection copied"); the + // (e.g. "/queue saved"); the // hint then auto-clears as soon as anything else // updates the slot. if app.status_message.is_none() { @@ -6482,18 +6502,7 @@ pub(crate) async fn run_event_loop( KeyCode::Char('c') | KeyCode::Char('C') if key_shortcuts::is_copy_shortcut(&key) => { - let sel = app.selected_text(); - if !sel.is_empty() { - if let Ok(transport) = app.clipboard.write_text_status(&sel) { - let receipt = copy_receipt(app, transport, "Copied to clipboard"); - app.push_status_toast(receipt, StatusToastLevel::Info, None); - app.clear_selection(); - } else { - app.push_status_toast("Copy failed", StatusToastLevel::Error, None); - } - } else { - copy_active_selection(app); - } + copy_active_selection(app); } KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => { // Four behaviors layered on Ctrl+C in priority order — see @@ -7419,14 +7428,14 @@ pub(super) async fn adopt_live_local_ollama_catalog( app.onboarding_needs_api_key = false; app.onboarding_missing_key_recovery = false; // A launch with no key opens the provider picker (#6566). The local model - // just answered that question, so close the picker and its onboarding - // step rather than leave a stale "connect a model" screen whose Esc would - // now walk back to the welcome screen. + // just answered that question, so close the picker and advance past its + // onboarding step rather than leave a stale "connect a model" screen whose + // Esc would now walk back to the welcome screen. if app.onboarding == OnboardingState::Provider { if app.view_stack.top_kind() == Some(ModalKind::ProviderPicker) { app.view_stack.pop(); } - app.onboarding = OnboardingState::None; + crate::tui::onboarding::advance_onboarding_after_provider(app); } // Say plainly which model is in use and how to change it, instead of the // endpoint it was discovered from (#6566). @@ -8571,10 +8580,13 @@ pub(super) fn route_key_to_view_stack( /// Keep only the Engine's retry receipts in the existing transcript. Ordinary /// status/footer behavior and internal/model-only status projection stay intact. pub(super) fn apply_engine_status(app: &mut App, message: String) -> bool { + if crate::core::events::is_retry_status_receipt(&message) { + app.add_message(HistoryCell::System { content: message }); + return true; + } // The account-profile fallback notice is sent once per engine; keep it in // the transcript so the next turn's status line cannot erase it. - let retain = crate::core::events::is_retry_status_receipt(&message) - || app.tr(MessageId::ProfileConstitutionUnavailableLocal) == message.as_str(); + let retain = app.tr(MessageId::ProfileConstitutionUnavailableLocal) == message.as_str(); if retain { app.add_message(HistoryCell::System { content: message.clone(), diff --git a/crates/tui/src/tui/ui/frame.rs b/crates/tui/src/tui/ui/frame.rs index 84fb88b44f..c1b9aef433 100644 --- a/crates/tui/src/tui/ui/frame.rs +++ b/crates/tui/src/tui/ui/frame.rs @@ -1922,10 +1922,11 @@ pub(crate) fn render(f: &mut Frame, app: &mut App, _config: &Config) -> Option<( // frame-derived explicit styled-surface mask, including aliased colors. if let Some(column) = shell_ocean { // The working canvas may keep a small responsive gutter, but the water - // does not stop at that content edge. Paint the cleared terminal floor - // first so wide layouts read as one ocean rather than a blue card - // floating between black banks. `paint_matching` leaves every semantic - // widget background untouched. + // does not stop at that content edge. One full-frame `surface_bg` pass + // paints the cleared terminal floor and every ordinary surface band + // so wide layouts read as one ocean rather than a blue card floating + // between black banks. `paint_matching` leaves every semantic widget + // background untouched. column.paint_matching_native( size, f.buffer_mut(), @@ -1933,38 +1934,6 @@ pub(crate) fn render(f: &mut Frame, app: &mut App, _config: &Config) -> Option<( &app.ui_theme, &app.viewport.ocean_semantic_surfaces, ); - if top_work_strip_height > 0 { - column.paint_matching_native( - body_chunks[strip_slot], - f.buffer_mut(), - app.ui_theme.surface_bg, - &app.ui_theme, - &app.viewport.ocean_semantic_surfaces, - ); - } - if let Some(side_area) = side_work_area { - column.paint_matching_native( - side_area, - f.buffer_mut(), - app.ui_theme.surface_bg, - &app.ui_theme, - &app.viewport.ocean_semantic_surfaces, - ); - } - column.paint_matching_native( - work_chat_area, - f.buffer_mut(), - app.ui_theme.surface_bg, - &app.ui_theme, - &app.viewport.ocean_semantic_surfaces, - ); - column.paint_matching_native( - body_chunks[preview_slot], - f.buffer_mut(), - app.ui_theme.surface_bg, - &app.ui_theme, - &app.viewport.ocean_semantic_surfaces, - ); if plugin_cta_height > 0 { column.paint_matching_native( body_chunks[plugin_cta_slot], diff --git a/crates/tui/src/tui/ui/handlers.rs b/crates/tui/src/tui/ui/handlers.rs index 7f9c831b19..cc8a1354ae 100644 --- a/crates/tui/src/tui/ui/handlers.rs +++ b/crates/tui/src/tui/ui/handlers.rs @@ -353,7 +353,7 @@ pub(crate) async fn handle_setup_constitution_model_draft( app.status_message = Some(match locale { codewhale_localization::Locale::ZhHans => { format!( - "{model_label} 正在生成协作准则草案……(最多 {}s)", + "{model_label} 正在生成宪章草案……(最多 {}s)", DRAFT_TIMEOUT.as_secs() ) } @@ -1244,30 +1244,20 @@ pub(crate) fn handle_shell_job_action(app: &mut App, action: crate::tui::app::Sh Err(err) => add_shell_job_message(app, format!("Command lookup failed: {err}")), } } - crate::tui::app::ShellJobAction::Poll { id, wait } => { - match manager.poll_delta_for_session( - &active_session_id, - &id, - wait, - if wait { 5_000 } else { 1_000 }, - ) { - Ok(delta) => add_shell_job_message(app, format_shell_poll(&delta.result)), - Err(err) => add_shell_job_message(app, format!("Command poll failed: {err}")), - } - } crate::tui::app::ShellJobAction::SendStdin { id, input, close } => { match manager.write_stdin_for_session(&active_session_id, &id, &input, close) { - Ok(()) => { - match manager.poll_delta_for_session(&active_session_id, &id, false, 1_000) { - Ok(delta) => add_shell_job_message(app, format_shell_poll(&delta.result)), - Err(err) => { - add_shell_job_message( - app, - format!("Command input sent; poll failed: {err}"), - ); - } + Ok(()) => match manager.inspect_job_for_session(&active_session_id, &id) { + Ok(detail) => add_shell_job_message( + app, + format_shell_job_list(std::slice::from_ref(&detail.snapshot)), + ), + Err(err) => { + add_shell_job_message( + app, + format!("Command input sent; poll failed: {err}"), + ); } - } + }, Err(err) => add_shell_job_message(app, format!("Command input failed: {err}")), } } diff --git a/crates/tui/src/tui/ui/task_projection.rs b/crates/tui/src/tui/ui/task_projection.rs index f71b17565d..bd2c40508e 100644 --- a/crates/tui/src/tui/ui/task_projection.rs +++ b/crates/tui/src/tui/ui/task_projection.rs @@ -625,8 +625,11 @@ pub(super) fn shell_exec_live_update( let next_status = shell_job_tool_status(&job.status); let next_live = shell_job_live_output(job).or_else(|| exec.live_output.clone()); let finalized = !matches!(job.status, ShellStatus::Running); - let stale_elapsed_since_output_ms = if matches!(job.status, ShellStatus::Running) && job.stale { - Some(job.elapsed_since_output_ms.unwrap_or(0)) + let quiet_after_ms = + u64::try_from(crate::tools::shell::QUIET_NO_OUTPUT_AFTER.as_millis()).unwrap_or(u64::MAX); + let stale_elapsed_since_output_ms = if matches!(job.status, ShellStatus::Running) { + job.elapsed_since_output_ms + .filter(|elapsed| *elapsed >= quiet_after_ms) } else { None }; diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index 91f0761f52..0cf24b0b6e 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -1435,11 +1435,7 @@ fn canonical_background_bash_keeps_live_task_identity_for_follow_up_actions() { assert_eq!(exec.shell_task_id.as_deref(), Some("shell-42")); assert_eq!(exec.command, "cargo test --workspace"); assert!(exec.output.is_none()); - assert!( - exec.live_output - .as_deref() - .is_some_and(|output| { output.contains("Background task started: shell-42") }) - ); + assert!(exec.live_output.is_none()); } #[test] @@ -4446,7 +4442,7 @@ fn selection_to_text_copies_rendered_transcript_block() { !selected.contains("Ctrl+O"), "detail affordance leaked into the selection: {selected:?}" ); - assert!(selected.contains("run Done · cargo check"), "{selected:?}"); + assert!(selected.contains("run done · cargo check"), "{selected:?}"); assert!(selected.contains("copy assistant"), "{selected:?}"); // #1163: tool-card middle lines are rendered with a `│ ` left rail // glyph, but that decoration must not leak into copied text. Assert @@ -4645,8 +4641,8 @@ fn mouse_selection_fragment_drag_copies_exact_text() { "must not round out to the whole cell, got {copied:?}" ); assert_eq!( - app.status_message.as_deref(), - Some("Selection copied"), + app.status_toasts.back().map(|toast| toast.text.as_str()), + Some("Copied to the clipboard"), "fragment copy reports through the text-fallback receipt" ); assert!( @@ -10189,7 +10185,7 @@ fn shell_live_output_update_marks_stale_running_job_static() { stdout_len: 14, stderr_len: 0, stdin_available: false, - stale: true, + stale: false, elapsed_since_output_ms: Some(61_000), linked_task_id: None, owner_agent_id: None, @@ -10232,7 +10228,7 @@ fn shell_live_output_update_marks_stale_running_job_static() { .iter() .map(|span| span.content.as_ref()) .collect::(); - assert!(header_text.contains("running · stale · no output 1m 01s")); + assert!(header_text.contains("running · no output for 1m 01s")); assert!(!header_text.contains("running (")); } @@ -10961,7 +10957,15 @@ async fn adopting_a_local_model_closes_the_connect_picker_and_names_it() { .await; assert_eq!(app.api_provider, ProviderKind::Ollama); - assert_eq!(app.onboarding, crate::tui::app::OnboardingState::None); + assert!( + matches!( + app.onboarding, + crate::tui::app::OnboardingState::TrustDirectory + | crate::tui::app::OnboardingState::Ready + ), + "{:?}", + app.onboarding + ); assert_ne!( app.view_stack.top_kind(), Some(crate::tui::views::ModalKind::ProviderPicker) @@ -22532,8 +22536,8 @@ fn completed_exec_tool_result_still_renders_run_done() { assert_eq!(exec.status, ToolStatus::Success); let text = rendered_text(&exec.lines_with_motion(100, true)); - assert!(text.contains("run Done"), "{text}"); - assert!(!text.contains("tool loaded - retry required"), "{text}"); + assert!(text.contains("run done"), "{text}"); + assert!(!text.contains("loaded, not run"), "{text}"); } /// #6566: the tool output the person reads drops the engine's approval note @@ -22619,8 +22623,8 @@ fn hydrated_exec_tool_result_renders_retry_required_not_run_done() { assert_eq!(exec.status, ToolStatus::Hydrated); let text = rendered_text(&exec.lines_with_motion(120, true)); - assert!(text.contains("run tool loaded - retry required"), "{text}"); - assert!(!text.contains("run Done"), "{text}"); + assert!(text.contains("run loaded, not run"), "{text}"); + assert!(!text.contains("run done"), "{text}"); } #[test] @@ -22657,8 +22661,8 @@ fn hydrated_tool_with_validation_body_still_uses_hydrated_status() { assert_eq!(generic.status, ToolStatus::Hydrated); let text = rendered_text(&HistoryCell::Tool(ToolCell::Generic(generic.clone())).lines(120)); - assert!(text.contains("tool loaded - retry required"), "{text}"); - assert!(!text.contains("tool Done"), "{text}"); + assert!(text.contains("tool loaded, not run"), "{text}"); + assert!(!text.contains("tool done"), "{text}"); } #[test] @@ -22693,8 +22697,8 @@ fn failed_tool_result_with_hydration_metadata_stays_failed() { assert_eq!(generic.status, ToolStatus::Failed); let text = rendered_text(&HistoryCell::Tool(ToolCell::Generic(generic.clone())).lines(120)); - assert!(text.contains("tool issue"), "{text}"); - assert!(!text.contains("tool loaded - retry required"), "{text}"); + assert!(text.contains("tool failed"), "{text}"); + assert!(!text.contains("loaded, not run"), "{text}"); } #[test] @@ -24250,7 +24254,7 @@ fn auto_route_receipt_survives_session_snapshot_and_restore() { restored_app.last_effective_reasoning_effort, Some(EffectiveReasoningEffort::Tier(ReasoningEffort::High)) ); - assert_eq!(restored_app.reasoning_effort_display_label(), "auto: high"); + assert_eq!(restored_app.reasoning_effort_display_label(), "auto→high"); } #[test] diff --git a/crates/tui/src/tui/views/help.rs b/crates/tui/src/tui/views/help.rs index 7ef802340b..08d487f0a4 100644 --- a/crates/tui/src/tui/views/help.rs +++ b/crates/tui/src/tui/views/help.rs @@ -1489,14 +1489,14 @@ mod tests { #[test] fn substring_filter_narrows_to_command() { let mut view = HelpView::new(); - type_filter(&mut view, "mode [act"); + type_filter(&mut view, "mode [work"); assert!(!view.filtered.is_empty()); // Every filtered entry should genuinely contain the query in its // searchable haystack — no false positives slipped past. for idx in &view.filtered { assert!( - view.entries[*idx].haystack.contains("mode [act"), - "entry {:?} leaked through `mode [act` filter", + view.entries[*idx].haystack.contains("mode [work"), + "entry {:?} leaked through `mode [work` filter", view.entries[*idx] ); } @@ -1506,7 +1506,7 @@ mod tests { view.filtered .iter() .any(|idx| view.entries[*idx].label == "/mode"), - "/mode should match the `mode [act` filter" + "/mode should match the `mode [work` filter" ); } @@ -2182,14 +2182,14 @@ mod tests { #[test] fn render_with_filter_shows_only_matching_section_and_status() { let mut view = HelpView::new(); - type_filter(&mut view, "mode [act"); + type_filter(&mut view, "mode [work"); let area = Rect::new(0, 0, 96, 24); let mut buf = Buffer::empty(area); view.render(area, &mut buf); let dump = buffer_text(&buf, area); assert!( - dump.contains("Filter: mode [act"), + dump.contains("Filter: mode [work"), "filter echo missing:\n{dump}" ); assert!( @@ -2202,7 +2202,7 @@ mod tests { ); assert!( !dump.contains("/model"), - "non-matching commands should not render under a `mode [act` filter:\n{dump}" + "non-matching commands should not render under a `mode [work` filter:\n{dump}" ); } diff --git a/crates/tui/src/tui/views/mod.rs b/crates/tui/src/tui/views/mod.rs index e4267abe1a..8f12325b22 100644 --- a/crates/tui/src/tui/views/mod.rs +++ b/crates/tui/src/tui/views/mod.rs @@ -1593,6 +1593,13 @@ impl ViewStack { panel.refresh_snapshot(snapshot); } } + + pub(crate) fn top_pager_mut(&mut self) -> Option<&mut crate::tui::pager::PagerView> { + self.views + .last_mut()? + .as_any_mut() + .downcast_mut::() + } } impl fmt::Debug for ViewStack { diff --git a/crates/tui/src/tui/widgets/approval_band_legacy.rs b/crates/tui/src/tui/widgets/approval_band_legacy.rs index 5cd390ac5f..653daea8e4 100644 --- a/crates/tui/src/tui/widgets/approval_band_legacy.rs +++ b/crates/tui/src/tui/widgets/approval_band_legacy.rs @@ -176,7 +176,7 @@ impl<'a> ApprovalWidget<'a> { } else { let mut rendered_detail = false; for detail in details.iter().take(4) { - let is_change_preview = matches!(detail.label.as_str(), "Preview" | "预览"); + let is_change_preview = detail.is_preview; if let Some(shell_lines) = detail.shell_lines.as_deref() { let command_width = area.width.saturating_sub(10) as usize; // A short approval band has room for only one detail row diff --git a/crates/tui/src/tui/widgets/mod.rs b/crates/tui/src/tui/widgets/mod.rs index ca6fa4e0cd..cd6b261d65 100644 --- a/crates/tui/src/tui/widgets/mod.rs +++ b/crates/tui/src/tui/widgets/mod.rs @@ -1692,7 +1692,7 @@ impl<'a> ApprovalWidget<'a> { } else { let mut rendered_detail = false; for detail in details.iter().take(4) { - let is_change_preview = matches!(detail.label.as_str(), "Preview" | "预览"); + let is_change_preview = detail.is_preview; if let Some(shell_lines) = detail.shell_lines.as_deref() { let command_width = area.width.saturating_sub(10) as usize; // A short approval band has room for only one detail row @@ -2528,16 +2528,15 @@ impl Renderable for ElevationWidget<'_> { let popup_width = 70.min(area.width.saturating_sub(4)); - let mut lines = vec![ - Line::from(""), - Line::from(vec![Span::styled( - tr(self.locale, MessageId::ElevationTitleSandboxDenied), - Style::default() - .fg(palette::STATUS_ERROR) - .add_modifier(Modifier::BOLD), - )]), - Line::from(""), - Line::from(vec![ + let mut lines = vec![match self.request.command.as_deref() { + Some(command) => Line::from(vec![ + Span::raw(tr(self.locale, MessageId::ElevationFieldCmd)), + Span::styled( + crate::utils::truncate_with_ellipsis(command, 45, "..."), + Style::default().fg(palette::TEXT_MUTED), + ), + ]), + None => Line::from(vec![ Span::raw(tr(self.locale, MessageId::ElevationFieldTool)), Span::styled( &self.request.tool_name, @@ -2546,15 +2545,7 @@ impl Renderable for ElevationWidget<'_> { .add_modifier(Modifier::BOLD), ), ]), - ]; - - if let Some(ref command) = self.request.command { - let cmd_display = crate::utils::truncate_with_ellipsis(command, 45, "..."); - lines.push(Line::from(vec![ - Span::raw(tr(self.locale, MessageId::ElevationFieldCmd)), - Span::styled(cmd_display, Style::default().fg(palette::TEXT_MUTED)), - ])); - } + }]; lines.push(Line::from("")); lines.push(Line::from(vec![ @@ -3844,7 +3835,7 @@ mod tests { !settled.contains("run running"), "flushed terminal state reused the active cache entry:\n{settled}" ); - assert!(settled.contains("run issue"), "{settled}"); + assert!(settled.contains("run failed"), "{settled}"); } fn render_approval_request( @@ -4300,7 +4291,7 @@ mod tests { !settled.contains("run running"), "history cell reused the active slow-path cache entry:\n{settled}" ); - assert!(settled.contains("run issue"), "{settled}"); + assert!(settled.contains("run failed"), "{settled}"); } #[test] diff --git a/crates/tui/src/tui/widgets/tool_card.rs b/crates/tui/src/tui/widgets/tool_card.rs index 45eb23a3a3..c05cac6370 100644 --- a/crates/tui/src/tui/widgets/tool_card.rs +++ b/crates/tui/src/tui/widgets/tool_card.rs @@ -63,7 +63,7 @@ pub enum ToolFamily { pub fn tool_family_for_title(title: &str) -> ToolFamily { match title { "Shell" => ToolFamily::Run, - "Patch" | "Diff" => ToolFamily::Patch, + "Patch" | "Diff" | "File" => ToolFamily::Patch, "Workspace" | "Image" => ToolFamily::Read, "Search" => ToolFamily::Find, "Plan" | "Legacy plan" | "Review" => ToolFamily::Generic, @@ -222,7 +222,7 @@ fn summary_value(summary: &str, key: &str) -> Option { None } -fn should_show_tool_name_in_header(name: &str, family: ToolFamily) -> bool { +pub(crate) fn should_show_tool_name_in_header(name: &str, family: ToolFamily) -> bool { (matches!(family, ToolFamily::Generic) && !is_known_metadata_tool_name(name)) || matches!(name, "git_log" | "git_show" | "git_blame") } diff --git a/crates/tui/src/tui/work_surface/model.rs b/crates/tui/src/tui/work_surface/model.rs index ef276f40a5..593c3a3753 100644 --- a/crates/tui/src/tui/work_surface/model.rs +++ b/crates/tui/src/tui/work_surface/model.rs @@ -981,16 +981,25 @@ fn durable_task_rows(app: &App) -> Vec { detail: format!("{status} · {}", entry.id), tone: bucket_tone(bucket), selectable: true, - primary_action: Some(SidebarRowAction::Command(format!( - "/jobs show {}", - entry.id - ))), + primary_action: task_show_action(entry), agent: None, } }) .collect() } +fn task_show_action(entry: &TaskPanelEntry) -> Option { + (!entry.id.starts_with("rlm-")) + .then(|| SidebarRowAction::Command(format!("/task show {}", entry.id))) +} + +fn shell_show_action(entry: &TaskPanelEntry) -> Option { + Some(SidebarRowAction::Command(format!( + "/jobs show {}", + entry.id + ))) +} + /// Finished shells and durable tasks, muted, each saying how it ended: /// `exit 0 · 12s`, `failed · exit 2`, `killed`, `timed out`. The shell /// leads with its command; its id is only in the detail and inspector. @@ -1020,11 +1029,7 @@ fn finished_background_rows(app: &App) -> Vec { detail: format!("{outcome} · {}", entry.id), tone, selectable: true, - primary_action: Some(SidebarRowAction::InspectWork { - title: format!("Shell {}", entry.id), - body: shell_inspector_body(app, entry, &command, &outcome), - stop_action: None, - }), + primary_action: shell_show_action(entry), agent: Some(AgentRowFacts { role_label: "shell".to_string(), status: outcome, @@ -1059,10 +1064,7 @@ fn finished_background_rows(app: &App) -> Vec { ), tone, selectable: true, - primary_action: Some(SidebarRowAction::Command(format!( - "/jobs show {}", - entry.id - ))), + primary_action: task_show_action(entry), agent: None, } } @@ -2635,14 +2637,7 @@ fn shell_work_rows(app: &App) -> Vec { detail: format!("{status} · {}", entry.id), tone: WorkTone::Live, selectable: true, - primary_action: Some(SidebarRowAction::InspectWork { - title: format!("Shell {}", entry.id), - body: shell_inspector_body(app, entry, command, status), - stop_action: Some(Box::new(SidebarRowAction::Command(format!( - "/jobs cancel {}", - entry.id - )))), - }), + primary_action: shell_show_action(entry), agent: Some(AgentRowFacts { role_label: "shell".to_string(), status: status.to_string(), @@ -2697,27 +2692,6 @@ fn shells_section_heading(shells: &[WorkRow]) -> WorkRow { } } -fn shell_inspector_body(app: &App, entry: &TaskPanelEntry, command: &str, status: &str) -> String { - let session = app.current_session_id.as_deref().unwrap_or(""); - if let Some(manager) = app.runtime_services.shell_manager.as_ref() - && let Ok(mut manager) = manager.try_lock() - && let Ok(detail) = manager.inspect_job_for_session(session, &entry.id) - { - let live = detail.snapshot.status == crate::tools::shell::ShellStatus::Running - && !detail.snapshot.stale; - let body = crate::tui::shell_job_routing::format_shell_job_detail(&detail); - return if live { - format!("Cancel: /jobs cancel {}\n\n{body}", entry.id) - } else { - body - }; - } - format!( - "Job: {}\nStatus: {status}\nCommand: {command}\n\nCancel: /jobs cancel {}\n\nOpen this row to watch live output.", - entry.id, entry.id - ) -} - fn graph_node_row(snapshot: &WorkGraphSnapshot, node: &WorkNode) -> WorkRow { let (mark, tone) = match node.state { NodeState::Ready => (crate::tui::glyphs::READY, WorkTone::Muted), @@ -4375,24 +4349,14 @@ mod tests { // #6565: the command leads; the id stays in the detail. assert_eq!(shell.label, "cd /workspace/example-project"); assert!(shell.detail.contains("shell_a1b2c3d4"), "{}", shell.detail); - let Some(SidebarRowAction::InspectWork { - title, - body, - stop_action, - }) = shell.primary_action.as_ref() - else { - panic!( - "shell row must open live output, got {:?}", - shell.primary_action - ); - }; - assert!(title.contains("shell_a1b2c3d4"), "{title}"); - assert!(body.contains("Job: shell_a1b2c3d4"), "{body}"); - assert!(body.contains("/jobs cancel shell_a1b2c3d4"), "{body}"); - assert!(matches!( - stop_action.as_deref(), - Some(SidebarRowAction::Command(command)) if command == "/jobs cancel shell_a1b2c3d4" - )); + assert!( + matches!( + shell.primary_action.as_ref(), + Some(SidebarRowAction::Command(command)) if command == "/jobs show shell_a1b2c3d4" + ), + "shell row must open the live inspector, got {:?}", + shell.primary_action + ); let facts = shell .agent .as_ref() @@ -4625,7 +4589,7 @@ mod tests { .find(|row| row.id.0 == format!("task:{id}")) .expect("task row"); assert!( - matches!(&row.primary_action, Some(SidebarRowAction::Command(command)) if command == &format!("/jobs show {id}")) + matches!(&row.primary_action, Some(SidebarRowAction::Command(command)) if command == &format!("/task show {id}")) ); } } diff --git a/crates/tui/src/utils.rs b/crates/tui/src/utils.rs index b6fba0ae53..5b509ccebe 100644 --- a/crates/tui/src/utils.rs +++ b/crates/tui/src/utils.rs @@ -417,8 +417,9 @@ fn write_atomic_with_permissions( /// once for the whole set — see [`write_atomic_batch`]. #[derive(Clone, Copy, PartialEq, Eq)] enum AtomicWriteScope { - /// Sweep this directory for stale temp files and fsync it: what a single - /// write should do, and what every caller of `write_atomic` gets. + /// Sweep this directory for stale temp files (at most once per + /// `STALE_AFTER`) and fsync it: what a single write should do, and what + /// every caller of `write_atomic` gets. Single, /// Leave both to the caller. Used only by [`write_atomic_batch`]. Batch, @@ -426,18 +427,18 @@ enum AtomicWriteScope { /// Write many files, and pay each directory's costs once. /// -/// Every [`write_atomic`] call sweeps its directory for stale temp files and -/// fsyncs that directory, which is exactly right for one record at a time. A -/// caller publishing a thousand records into one directory pays that thousand -/// times, though, and the sweep is the same answer every time: scanning a -/// store directory of tens of thousands of entries per file is minutes of work -/// that buys nothing (measured: 22 ms per item write, 34 s for one fork's -/// clone). +/// Every [`write_atomic`] call fsyncs its directory, which is exactly right +/// for one record at a time. A caller publishing a thousand records into one +/// directory pays that thousand times, though. The stale-temp sweep is +/// already throttled to once per directory per `STALE_AFTER`, because +/// scanning a store directory of tens of thousands of entries per file is +/// minutes of work that buys nothing (measured before the throttle: 22 ms per +/// item write, 34 s for one fork's clone). /// -/// The batch sweeps each directory once, writes every file with the same -/// atomic replace and per-file data sync, and fsyncs each directory once at -/// the end. Per-file durability is unchanged; only the per-file directory work -/// is hoisted out of the loop. +/// The batch goes through the same throttled sweep once per directory, writes +/// every file with the same atomic replace and per-file data sync, and fsyncs +/// each directory once at the end. Per-file durability is unchanged; only the +/// per-file directory work is hoisted out of the loop. /// /// Ordering is still the caller's job: a batch that publishes a graph of /// records must write its commit record last, as the single-write callers do. @@ -451,9 +452,7 @@ pub fn write_atomic_batch(files: &[(PathBuf, Vec)]) -> std::io::Result<()> { } } for parent in &parents { - if is_codewhale_owned_state_dir(parent) { - sweep_stale_atomic_write_temps(parent); - } + sweep_owned_dir_if_due(parent); } for (path, contents) in files { write_atomic_scoped( @@ -571,14 +570,12 @@ fn write_atomic_scoped( builder.permissions(fs::Permissions::from_mode(0o666)); } - // Reclaim our own strays before adding another (see the function docs). + // Reclaim our own strays before adding another, at most once per + // directory per `STALE_AFTER` (see `sweep_stale_atomic_write_temps`). // Private permission policy is also used for user-chosen destinations // such as `/save `; only sweep Codewhale-owned state/config dirs. - if permission_policy == AtomicWritePermissions::Private - && scope == AtomicWriteScope::Single - && is_codewhale_owned_state_dir(parent) - { - sweep_stale_atomic_write_temps(parent); + if permission_policy == AtomicWritePermissions::Private && scope == AtomicWriteScope::Single { + sweep_owned_dir_if_due(parent); } // Validated before any temp exists, so a refused name leaves nothing. @@ -688,6 +685,34 @@ fn is_codewhale_owned_state_dir(dir: &Path) -> bool { }) } +const STALE_AFTER: std::time::Duration = std::time::Duration::from_secs(60 * 60); + +fn sweep_owned_dir_if_due(dir: &Path) { + use std::collections::HashMap; + use std::sync::{Mutex, OnceLock, PoisonError}; + use std::time::Instant; + + static LAST_SWEPT: OnceLock>> = OnceLock::new(); + let now = Instant::now(); + { + let mut last_swept = LAST_SWEPT + .get_or_init(Default::default) + .lock() + .unwrap_or_else(PoisonError::into_inner); + if last_swept + .get(dir) + .is_some_and(|swept| now.saturating_duration_since(*swept) < STALE_AFTER) + { + return; + } + last_swept.retain(|_, swept| now.saturating_duration_since(*swept) < STALE_AFTER); + last_swept.insert(dir.to_path_buf(), now); + } + if is_codewhale_owned_state_dir(dir) { + sweep_stale_atomic_write_temps(dir); + } +} + /// Remove `.tmpXXXXXX` files this writer stranded in `dir` on an earlier run. /// /// `NamedTempFile` deletes itself on drop, so an ordinary failure — or an @@ -712,7 +737,6 @@ fn is_codewhale_owned_state_dir(dir: &Path) -> bool { /// - **Best effort** — every failure is ignored; this must never turn a /// successful write into an error. fn sweep_stale_atomic_write_temps(dir: &Path) { - const STALE_AFTER: std::time::Duration = std::time::Duration::from_secs(60 * 60); let Ok(entries) = fs::read_dir(dir) else { return; }; @@ -1198,9 +1222,10 @@ mod atomic_write_tests { /// A batch writes every file, and pays the directory's hygiene once. /// - /// The per-file path sweeps the directory for stale temp files and fsyncs - /// it on every call; a fork publishing hundreds of cloned items paid that - /// hundreds of times (22 ms of directory scan each, 34 s for one fork). + /// The per-file path fsyncs the directory on every call, and used to sweep + /// it for stale temp files on every call too; a fork publishing hundreds + /// of cloned items paid that hundreds of times (22 ms of directory scan + /// each, 34 s for one fork). /// What must not change: every file lands with its content, a stray temp /// file is still reclaimed, and none of ours is left behind. #[test] diff --git a/crates/tui/tests/fixtures/conformance/events/approval_denied.golden.jsonl b/crates/tui/tests/fixtures/conformance/events/approval_denied.golden.jsonl index d5e054ccb7..4d586bac04 100644 --- a/crates/tui/tests/fixtures/conformance/events/approval_denied.golden.jsonl +++ b/crates/tui/tests/fixtures/conformance/events/approval_denied.golden.jsonl @@ -1,8 +1,8 @@ {"created_at":"","event":"turn_started","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Create denied.txt with touch.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"changed":false,"context_updates":0,"description":"frozen: 54603624f5a8","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"changed":false,"context_updates":0,"description":"frozen: bcbbcfbebef5","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"route_dispatched","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing":{"billing_mode":"metered","dispatched_at":""},"billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":150,"output_tokens":15}} {"event":"tool_call_started","input":{"command":"touch denied.txt"},"tool_call_id":"","tool_name":"Bash"} @@ -12,12 +12,12 @@ {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Create denied.txt with touch.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"execution_id":"","id":"call_touch","input":{"command":"touch denied.txt"},"name":"Bash","type":"tool_use"}],"role":"assistant"},{"content":[{"content":"Error: Tool 'Bash' denied by user — the call was not approved. Do not retry the same call; present what you intended and wait for the user's approval or new instructions.","execution_id":"","is_error":true,"tool_use_id":"call_touch","type":"tool_result"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"event":"status","message":"Continuing — tool results"} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"message_started","index":0} {"delta":"Understood, I did not create it.","event":"response_delta","index":0} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":200,"output_tokens":6}} {"event":"message_complete","index":0} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Create denied.txt with touch.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"execution_id":"","id":"call_touch","input":{"command":"touch denied.txt"},"name":"Bash","type":"tool_use"}],"role":"assistant"},{"content":[{"content":"Error: Tool 'Bash' denied by user — the call was not approved. Do not retry the same call; present what you intended and wait for the user's approval or new instructions.","execution_id":"","is_error":true,"tool_use_id":"call_touch","type":"tool_result"}],"role":"user"},{"content":[{"text":"Understood, I did not create it.","type":"text"}],"role":"assistant"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":200,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":2,"model_step_index":1,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":200,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":2,"model_step_index":1,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"turn_complete","parent_route_usage":{"input_tokens":350,"output_tokens":21},"routed_usage_dropped_records":0,"status":"completed","tool_catalog":"","usage":{"input_tokens":350,"output_tokens":21}} -{"harness_summary":{"model_requests":2,"non_streaming_requests":0,"workspace_after":{".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","README.md":"41f49bffb38de5ba"}}} +{"harness_summary":{"model_requests":2,"non_streaming_requests":0,"workspace_after":{".codewhale/state/.gitignore":"cdbcae15105d6b78",".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","README.md":"41f49bffb38de5ba"}}} diff --git a/crates/tui/tests/fixtures/conformance/events/cancel_midstream.golden.jsonl b/crates/tui/tests/fixtures/conformance/events/cancel_midstream.golden.jsonl index 65f17cbaf7..46d85be322 100644 --- a/crates/tui/tests/fixtures/conformance/events/cancel_midstream.golden.jsonl +++ b/crates/tui/tests/fixtures/conformance/events/cancel_midstream.golden.jsonl @@ -1,15 +1,15 @@ {"created_at":"","event":"turn_started","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Tell me a long story.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"changed":false,"context_updates":0,"description":"frozen: 8b8238c51355","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"changed":false,"context_updates":0,"description":"frozen: e6c0d3cc59cd","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"route_dispatched","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing":{"billing_mode":"metered","dispatched_at":""},"billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"event":"message_started","index":0} {"delta":"Here is a partial","event":"response_delta","index":0} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":120,"output_tokens":0}} {"event":"status","message":"Request cancelled"} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Tell me a long story.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"text":"Here is a partial","type":"text"}],"role":"assistant_interrupted"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":null,"last_reported_input_tokens":120,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":null,"model_requests_started":1,"model_step_index":0,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"interrupted","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"interrupted","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":null,"last_reported_input_tokens":120,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":null,"model_requests_started":1,"model_step_index":0,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"interrupted","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"interrupted","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"turn_complete","parent_route_usage":{"input_tokens":120,"output_tokens":0},"routed_usage_dropped_records":0,"status":"interrupted","tool_catalog":"","usage":{"input_tokens":120,"output_tokens":0}} {"event":"status","message":"Turn interrupted."} -{"harness_summary":{"model_requests":1,"non_streaming_requests":0,"workspace_after":{".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} +{"harness_summary":{"model_requests":1,"non_streaming_requests":0,"workspace_after":{".codewhale/state/.gitignore":"cdbcae15105d6b78",".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} diff --git a/crates/tui/tests/fixtures/conformance/events/one_tool_call.golden.jsonl b/crates/tui/tests/fixtures/conformance/events/one_tool_call.golden.jsonl index 0b16ad8f05..f30f81b017 100644 --- a/crates/tui/tests/fixtures/conformance/events/one_tool_call.golden.jsonl +++ b/crates/tui/tests/fixtures/conformance/events/one_tool_call.golden.jsonl @@ -1,8 +1,8 @@ {"created_at":"","event":"turn_started","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"What does README.md say?","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nActive paths (prioritize these):\n- README.md (file)\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"changed":false,"context_updates":0,"description":"frozen: 8b8238c51355","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"changed":false,"context_updates":0,"description":"frozen: e6c0d3cc59cd","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"route_dispatched","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing":{"billing_mode":"metered","dispatched_at":""},"billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":150,"output_tokens":20}} {"event":"tool_call_started","input":{"action":"read","path":"README.md"},"tool_call_id":"","tool_name":"File"} @@ -13,12 +13,12 @@ {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"What does README.md say?","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nActive paths (prioritize these):\n- README.md (file)\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"execution_id":"","id":"call_read_readme","input":{"action":"read","path":"README.md"},"name":"File","type":"tool_use"}],"role":"assistant"},{"content":[{"content":"content_hash=\"sha256:41f49bffb38de5ba88945f09121ffc590f9d7f6ff80fdb9ea8ad10224fecea61\"\nconformance fixture","execution_id":"","tool_use_id":"call_read_readme","type":"tool_result"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"event":"status","message":"Continuing — tool results"} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"message_started","index":0} {"delta":"It says: conformance fixture.","event":"response_delta","index":0} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":200,"output_tokens":6}} {"event":"message_complete","index":0} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"What does README.md say?","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nActive paths (prioritize these):\n- README.md (file)\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"execution_id":"","id":"call_read_readme","input":{"action":"read","path":"README.md"},"name":"File","type":"tool_use"}],"role":"assistant"},{"content":[{"content":"content_hash=\"sha256:41f49bffb38de5ba88945f09121ffc590f9d7f6ff80fdb9ea8ad10224fecea61\"\nconformance fixture","execution_id":"","tool_use_id":"call_read_readme","type":"tool_result"}],"role":"user"},{"content":[{"text":"It says: conformance fixture.","type":"text"}],"role":"assistant"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":200,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":2,"model_step_index":1,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":200,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":2,"model_step_index":1,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"turn_complete","parent_route_usage":{"input_tokens":350,"output_tokens":26},"routed_usage_dropped_records":0,"status":"completed","tool_catalog":"","usage":{"input_tokens":350,"output_tokens":26}} -{"harness_summary":{"model_requests":2,"non_streaming_requests":0,"workspace_after":{".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} +{"harness_summary":{"model_requests":2,"non_streaming_requests":0,"workspace_after":{".codewhale/state/.gitignore":"cdbcae15105d6b78",".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} diff --git a/crates/tui/tests/fixtures/conformance/events/parallel_tool_calls.golden.jsonl b/crates/tui/tests/fixtures/conformance/events/parallel_tool_calls.golden.jsonl index ef8df071b5..1ff8cfc455 100644 --- a/crates/tui/tests/fixtures/conformance/events/parallel_tool_calls.golden.jsonl +++ b/crates/tui/tests/fixtures/conformance/events/parallel_tool_calls.golden.jsonl @@ -1,8 +1,8 @@ {"created_at":"","event":"turn_started","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Read README.md and NOTES.md.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nActive paths (prioritize these):\n- NOTES.md (file)\n- README.md (file)\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"changed":false,"context_updates":0,"description":"frozen: 8b8238c51355","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"changed":false,"context_updates":0,"description":"frozen: e6c0d3cc59cd","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"route_dispatched","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing":{"billing_mode":"metered","dispatched_at":""},"billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":160,"output_tokens":40}} {"event":"tool_call_started","input":{"action":"read","path":"README.md"},"tool_call_id":"","tool_name":"File"} @@ -19,12 +19,12 @@ {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Read README.md and NOTES.md.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nActive paths (prioritize these):\n- NOTES.md (file)\n- README.md (file)\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"execution_id":"","id":"call_read_a","input":{"action":"read","path":"README.md"},"name":"File","type":"tool_use"},{"execution_id":"","id":"call_read_b","input":{"action":"read","path":"NOTES.md"},"name":"File","type":"tool_use"}],"role":"assistant"},{"content":[{"content":"content_hash=\"sha256:41f49bffb38de5ba88945f09121ffc590f9d7f6ff80fdb9ea8ad10224fecea61\"\nconformance fixture","execution_id":"","tool_use_id":"call_read_a","type":"tool_result"}],"role":"user"},{"content":[{"content":"content_hash=\"sha256:f957b19529906961933c5c30f8713c500a9bb5d9d0695c40d48c97a26a3594ec\"\nsecond file","execution_id":"","tool_use_id":"call_read_b","type":"tool_result"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"event":"status","message":"Continuing — tool results"} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"message_started","index":0} {"delta":"Both files read.","event":"response_delta","index":0} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":200,"output_tokens":6}} {"event":"message_complete","index":0} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Read README.md and NOTES.md.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nActive paths (prioritize these):\n- NOTES.md (file)\n- README.md (file)\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"execution_id":"","id":"call_read_a","input":{"action":"read","path":"README.md"},"name":"File","type":"tool_use"},{"execution_id":"","id":"call_read_b","input":{"action":"read","path":"NOTES.md"},"name":"File","type":"tool_use"}],"role":"assistant"},{"content":[{"content":"content_hash=\"sha256:41f49bffb38de5ba88945f09121ffc590f9d7f6ff80fdb9ea8ad10224fecea61\"\nconformance fixture","execution_id":"","tool_use_id":"call_read_a","type":"tool_result"}],"role":"user"},{"content":[{"content":"content_hash=\"sha256:f957b19529906961933c5c30f8713c500a9bb5d9d0695c40d48c97a26a3594ec\"\nsecond file","execution_id":"","tool_use_id":"call_read_b","type":"tool_result"}],"role":"user"},{"content":[{"text":"Both files read.","type":"text"}],"role":"assistant"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":200,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":2,"model_step_index":1,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":1,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":200,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":2,"model_step_index":1,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"turn_complete","parent_route_usage":{"input_tokens":360,"output_tokens":46},"routed_usage_dropped_records":0,"status":"completed","tool_catalog":"","usage":{"input_tokens":360,"output_tokens":46}} -{"harness_summary":{"model_requests":2,"non_streaming_requests":0,"workspace_after":{".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} +{"harness_summary":{"model_requests":2,"non_streaming_requests":0,"workspace_after":{".codewhale/state/.gitignore":"cdbcae15105d6b78",".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} diff --git a/crates/tui/tests/fixtures/conformance/events/plain_answer.golden.jsonl b/crates/tui/tests/fixtures/conformance/events/plain_answer.golden.jsonl index fdae81e851..0da424cd53 100644 --- a/crates/tui/tests/fixtures/conformance/events/plain_answer.golden.jsonl +++ b/crates/tui/tests/fixtures/conformance/events/plain_answer.golden.jsonl @@ -1,8 +1,8 @@ {"created_at":"","event":"turn_started","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Say hello.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"changed":false,"context_updates":0,"description":"frozen: 8b8238c51355","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"changed":false,"context_updates":0,"description":"frozen: e6c0d3cc59cd","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"route_dispatched","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing":{"billing_mode":"metered","dispatched_at":""},"billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"event":"message_started","index":0} {"delta":"Hello","event":"response_delta","index":0} @@ -10,6 +10,6 @@ {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":120,"output_tokens":4}} {"event":"message_complete","index":0} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Say hello.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Ask\nCurrent sandbox posture: workspace-write (writes inside the workspace; network blocked) (local OS sandbox applied)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"},{"content":[{"text":"Hello there.","type":"text"}],"role":"assistant"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":120,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":1,"model_step_index":0,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":{"truncated":false,"value":"end_turn"},"last_reported_input_tokens":120,"last_response_tool_calls":0,"last_response_tool_calls_suppressed":0,"model_requests_started":1,"model_step_index":0,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"provider_no_tool_call","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"completed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"turn_complete","parent_route_usage":{"input_tokens":120,"output_tokens":4},"routed_usage_dropped_records":0,"status":"completed","tool_catalog":"","usage":{"input_tokens":120,"output_tokens":4}} -{"harness_summary":{"model_requests":1,"non_streaming_requests":0,"workspace_after":{".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} +{"harness_summary":{"model_requests":1,"non_streaming_requests":0,"workspace_after":{".codewhale/state/.gitignore":"cdbcae15105d6b78",".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} diff --git a/crates/tui/tests/fixtures/conformance/events/provider_error_after_tool_call.golden.jsonl b/crates/tui/tests/fixtures/conformance/events/provider_error_after_tool_call.golden.jsonl index affd26f34c..b3f8a6585b 100644 --- a/crates/tui/tests/fixtures/conformance/events/provider_error_after_tool_call.golden.jsonl +++ b/crates/tui/tests/fixtures/conformance/events/provider_error_after_tool_call.golden.jsonl @@ -1,13 +1,13 @@ {"created_at":"","event":"turn_started","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"engine_session_id":"conformance-session","event":"session_updated","messages":[{"content":[{"text":"Write c0205.txt.","type":"text"},{"text":"\nCurrent local date: \nCurrent workspace: \nCurrent permission posture: Full Access\nCurrent sandbox posture: full access (sandbox disabled)\n## Repo Working Set\nKey files: README.md\nWhen in doubt, use tools to verify and keep changes focused on the working set.\n","type":"text"}],"role":"user"}],"model":"deepseek-v4-pro","system_prompt":"","workspace":""} {"changed":false,"context_updates":0,"description":"","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"changed":false,"context_updates":0,"description":"frozen: 8b8238c51355","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"changed":false,"context_updates":0,"description":"frozen: e6c0d3cc59cd","event":"prefix_cache_change","last_miss_reason":"","pin_reason":"initial","pinned_combined_hash":"","stability_pct":100,"system_prompt_changed":false,"tools_changed":false} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"event":"route_dispatched","route":{"auto_model":false,"base_url":"https://api.deepseek.com/beta","billing":{"billing_mode":"metered","dispatched_at":""},"billing_product":{"kind":"unproven"},"model":"deepseek-v4-pro","provider":"deepseek","provider_identity":"deepseek"},"turn_id":""} {"category":"invalid_input","code":"invalid_input","event":"error","message":"Model not exist.","recoverable":false,"severity":"error"} {"duration_ms":"","event":"turn_usage","first_token_ms":"","request_ms":"","usage":{"input_tokens":120,"output_tokens":0}} {"event":"tool_call_started","input":{"action":"write","content":"side effect\n","path":"c0205.txt"},"tool_call_id":"","tool_name":"File"} {"event":"tool_call_complete","result":{"content":"Not executed: the provider stream failed before the model response completed (Model not exist.).","metadata":{"error_category":"model_stream_failed","model_output_incomplete":true,"side_effect_status":"not_started"},"outcome":"ok","success":false},"tool_call_id":"","tool_name":"File"} -{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"18c6d652f11c0c195e7b586852ab46b47987939aaa316b39ef8b692255a7e077","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14890,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":null,"last_reported_input_tokens":120,"last_response_tool_calls":1,"last_response_tool_calls_suppressed":1,"model_requests_started":1,"model_step_index":0,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"failed","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"failed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-open and c"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} +{"event":"tool_request_snapshot","snapshot":{"active_tool_catalog_sha256":"ba34408b0c03b810ba1ef6190c41d215f58e88822148991099b7d70d444992fc","capture_source":"prepared model-client request","delivery_status":"unknown (capture does not prove provider delivery)","omitted_tool_count":0,"payload_json_bytes":14897,"payload_measurement_status":"exact (within 1048576-byte measurement bound)","provider":{"model":"deepseek-v4-pro","provider":"Deepseek","status":"available"},"registry_facts_present":true,"registry_only_tools":{"status":"known","value":{"count":40,"omitted":8,"rendered":[{"truncated":false,"value":"Git"},{"truncated":false,"value":"Run"},{"truncated":false,"value":"Web"},{"truncated":false,"value":"apply_patch"},{"truncated":false,"value":"automation"},{"truncated":false,"value":"diagnostics"},{"truncated":false,"value":"finance"},{"truncated":false,"value":"github"},{"truncated":false,"value":"grep_files"},{"truncated":false,"value":"handle_read"},{"truncated":false,"value":"harness"},{"truncated":false,"value":"image_ocr"},{"truncated":false,"value":"list_dir"},{"truncated":false,"value":"lsp"},{"truncated":false,"value":"note"},{"truncated":false,"value":"notify"},{"truncated":false,"value":"pandoc_convert"},{"truncated":false,"value":"project_map"},{"truncated":false,"value":"registry_sync"},{"truncated":false,"value":"request_plugin_install"},{"truncated":false,"value":"request_user_input"},{"truncated":false,"value":"retrieve_tool_result"},{"truncated":false,"value":"revert_turn"},{"truncated":false,"value":"review"},{"truncated":false,"value":"send_later"},{"truncated":false,"value":"session_get"},{"truncated":false,"value":"session_search"},{"truncated":false,"value":"start_mcp_server"},{"truncated":false,"value":"start_registry_mcp_server"},{"truncated":false,"value":"task_shell_wait"},{"truncated":false,"value":"tasks"},{"truncated":false,"value":"terminal/cancel"}]}},"registry_tool_count":{"status":"known","value":62},"rendered_tool_count":12,"schema_version":1,"step":0,"terminal":{"automatic_compaction_attempts":0,"effective_max_steps":null,"emergency_compaction_attempts":0,"empty_stop_retries":0,"final_report_requested":false,"last_prepared_output_limit_tokens":65536,"last_provider_finish_reason":null,"last_reported_input_tokens":120,"last_response_tool_calls":1,"last_response_tool_calls_suppressed":1,"model_requests_started":1,"model_step_index":0,"permission_denial_rounds_without_progress":0,"permission_strategy_switches":0,"reason":"failed","reasoning_only_reprompts":0,"route_context_window_tokens":1000000,"soft_landing_sent":false,"status":"failed","step_budget_source":"max_steps","stream_resumes":0,"transparent_stream_retries":0,"transport_retries":0},"tool_count":12,"tools":[{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Required"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"ExecutesCode"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Execute a shell command in the workspace and return stdout and stderr. Output keeps the last 2000 lines or 50KB. An optional timeout is the seconds to wait in the foreground (default 30 seconds); a command still running then is never killed for time: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id, so long builds and tests need no special timeout. Find task_shell_wait with tool_search to read more or wait for it. In Ask, after "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"command\":{\"description\":\"The command to execute. Actual execution shell: `/bin/bash`. Use Bash syntax: pipelines, redirections, $(command), and && / || are supported. Quote paths and variable expansions, such as \\\"$path\\\"; use single quotes for literal text. For literal multiline input, use a quoted heredoc delimiter (<<'EOF') with its closing delimiter on a separate line. Use only installed programs; do not assume GNU-specific flags on macOS/BSD. Example: printf '%s\\\\n' 'sample'.\",\"type\":\"string\"},\"justification\":{\"description\":\"Required with sandbox_permissions: one sentence explaining why this exact command needs wider access.\",\"type\":\"string\"},\"read_only\":{\"description\":\"Set true to run analysis code (including Python/SQLite) with mandatory native filesystem read-only isolation and no network. Available during peer writes. Refused when native enforcement is unavailable; no background, stdin, external backend, or sandbox escalation.\",\"type\":\"boolean\"},\"sandbox_permissions\":{\"description\":\"The wider sandbox mode this exact command needs. Use only as a one-shot retry after a sandbox denial; requires justification and user approval in Ask.\",\"enum\":[\"workspace-write\",\"danger-full-access\"],\"type\":\"string\"},\"timeout\":{\"description\":\"Optional seconds to wait in the foreground (default 30 seconds). A command still running then is not killed: it moves to the background by itself and you get its output so far, how long ago it last printed, its build phase, and a task_id. Find task_shell_wait with tool_search to read more or wait for it.\",\"type\":\"number\"}},\"required\":[\"command\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"bash"},"ordinal":1,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Create the session's one persistent goal: a completion objective Codewhale keeps working toward across turns until it is verified complete, blocked, or the user stops it. A goal is for a durable objective that outlasts one turn: a multi-step outcome the user wants continued and verified. A question, a greeting, or a one-shot edit completes as an ordinary turn. When the user explicitly asks to use `/goal` or to make something the goal, `create_goal` is what records it; acknowledging it in prose records nothi"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"objective\":{\"description\":\"The full objective to pursue. Keep the complete user goal, not a shortened one-turn version.\",\"type\":\"string\"},\"token_budget\":{\"description\":\"Optional soft token budget for the goal.\",\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"objective\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"create_goal"},"ordinal":2,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Edit one file with targeted text replacements. Every edits[].oldText must identify a unique, non-overlapping region of the original file. Merge nearby or overlapping changes into one edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"edits\":{\"description\":\"One or more disjoint replacements, all matched against the original file.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"newText\":{\"description\":\"Replacement text; may be empty to delete the matched span.\",\"type\":\"string\"},\"oldText\":{\"description\":\"Text identifying one unique region to replace.\",\"type\":\"string\"}},\"required\":[\"newText\",\"oldText\"],\"type\":\"object\"},\"type\":\"array\"},\"path\":{\"description\":\"Path to the file to edit (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"edits\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"edit"},"ordinal":3,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Find workspace files by name, path, or glob (e.g. src/**/*.rs). Space-separated terms must all match. Literal matches rank above fuzzy matches; results are capped. Respects ignore files and skips build/dependency directories by default. Use extensions to filter suffixes."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"exclude\":{\"description\":\"Optional replacement exclusion globs (e.g. [\\\"**/target/**\\\", \\\"*.lock\\\"]); [] disables default exclusions.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"extensions\":{\"description\":\"Optional list of file extensions to include (e.g. [\\\"rs\\\", \\\"md\\\"]).\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"limit\":{\"description\":\"Maximum number of ranked results to return (default: 20, maximum: 200).\",\"type\":\"integer\"},\"path\":{\"description\":\"Optional base path to search (relative to workspace).\",\"type\":\"string\"},\"query\":{\"description\":\"File name, path fragment, space-separated terms, or glob (e.g. **/engine*.rs).\",\"type\":\"string\"}},\"required\":[\"query\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"file_search"},"ordinal":4,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Inspect the current runtime goal state, including objective, status, token budget, elapsed time, evidence, and blocker."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"get_goal"},"ordinal":5,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Load a named skill's SKILL.md body and companion file list into this turn. Use when the user names a skill, or when an entry in the system prompt's `## Skills` index matches the task -- load it before starting the work, not after. Pass query=\"...\" to search names and descriptions, or name=\"list\" for the whole catalogue. Resolves global and plugin skills that `read` cannot reach."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"name\":{\"description\":\"Skill id to load. Omit or pass \\\"list\\\" to see all available skills.\",\"type\":\"string\"},\"query\":{\"description\":\"Search term matched against skill names and descriptions. Use when the index was truncated or no name is known.\",\"type\":\"string\"}},\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"load_skill"},"ordinal":6,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":2,"omitted":0,"rendered":[{"truncated":false,"value":"ReadOnly"},{"truncated":false,"value":"Sandboxable"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Read a file. A text file comes back whole in one call when it fits this call's output budget — 100000 bytes by default, raisable to 500000 with max_bytes. There is no line cap. Use offset and limit for an exact line range; when output is budget-limited the footer names the exact offset to continue from. Every text response reports the file's byte size, line count, and whether output was truncated. A PNG, JPEG, GIF or WebP image comes back as image content you can see (large images are downscaled), including"},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"limit\":{\"description\":\"Maximum number of lines to read.\",\"type\":\"number\"},\"max_bytes\":{\"description\":\"Output budget in bytes for this one call. Defaults to 100000; values above the 500000 maximum are clamped down rather than rejected, and a value below the active default leaves the default in place.\",\"type\":\"number\"},\"offset\":{\"description\":\"Line number to start reading from (1-indexed).\",\"type\":\"number\"},\"path\":{\"description\":\"Path to the file to read (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"read"},"ordinal":7,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Replace the To-do list the user watches. For any task with three or more steps or more than one file, write the list before you start, keep exactly one item in_progress, and mark items done as you finish them. Skip it only for a single quick answer or edit."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"properties\":{\"todos\":{\"description\":\"The complete list of To-do items. This replaces the existing list.\",\"items\":{\"properties\":{\"content\":{\"description\":\"The task description\",\"type\":\"string\"},\"status\":{\"description\":\"Task status\",\"enum\":[\"pending\",\"in_progress\",\"completed\",\"cancelled\"],\"type\":\"string\"}},\"required\":[\"content\",\"status\"],\"type\":\"object\"},\"type\":\"array\"}},\"required\":[\"todos\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"todo_write"},"ordinal":8,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Auto"}},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"status":"known","value":{"count":0,"omitted":0,"rendered":[]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Update the runtime goal completion gate by calling this tool; a prose status in your answer does not change the goal or stop continuation. Critical verification may seal one immutable completion contract. Advisory review is append-only context and never completes, blocks, or pauses the goal. Mark blocked when progress requires user input. Mark yield when you finished a stage and the next step needs the user's decision: the goal stays unfinished, the turn ends, and their next message resumes it."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":true,"value":"{\"additionalProperties\":false,\"properties\":{\"advisory\":{\"description\":\"Required when status is advisory. Appended separately from the judged completion contract.\",\"type\":\"string\"},\"blocker\":{\"description\":\"Required when status is blocked. Explain the condition preventing progress.\",\"type\":\"string\"},\"evidence\":{\"description\":\"Required when status is complete. Briefly cite the proof that the goal is done.\",\"type\":\"string\"},\"progress\":{\"additionalProperties\":false,\"description\":\"Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.\",\"properties\":{\"next\":{\"description\":\"One short line: what comes next.\",\"type\":\"string\"},\"now\":{\"description\":\"One short line: what is being worked on right now.\",\"type\":\"string\"},\"percent\":{\"description\":\"Estimated percent complete, 0-100.\",\"maximum\":100,\"minimum\":0,\"type\":\"integer\"}},\"required\":[\"percent\"],\"type\":\"object\"},\"status\":{\"description\":\"Use complete only when a critical verifier proves the goal; not_achieved to record verifier gaps; blocked when meaningful progress cannot continue; yield when a stage is finished and the next step is the user's call; advisory to append best-effort context without changing lifecycle state.\",\"enum\":[\"complete\",\"blocked\",\"not_achieved\",\"advisory\",\"yield\"],\"type\":\"string\"},\"verification\":{\"additionalProperties\":false,\"description\":\"Required when status is complete or not_achieved. A verifier-as-judge receipt from a concrete check, such as Run action=\\\"verifiers\\\" or an equivalent project-specific gate.\",\"properties\":{\"check\":{\"description\":\"The verifier/check that passed.\",\"type\":\"string\"},\"gaps\":{\"description\":\"Concrete remaining gaps. Required for critical not_achieved reviews; order and duplicate wording do not affect the stall fingerprint.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"role\":{\"description\":\"Critical reviews may satisfy the judged completion contract. Advisory reviews are fail-ope"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"update_goal"},"ordinal":9,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"status":"known","value":{"truncated":false,"value":"Suggest"}},"cache_control_type":{"status":"known","value":{"truncated":false,"value":"ephemeral"}},"capabilities":{"status":"known","value":{"count":3,"omitted":0,"rendered":[{"truncated":false,"value":"WritesFiles"},{"truncated":false,"value":"Sandboxable"},{"truncated":false,"value":"RequiresApproval"}]}},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Write content to a file. Creates the file if it does not exist, overwrites it if it does, and creates parent directories automatically."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"additionalProperties\":false,\"properties\":{\"content\":{\"description\":\"Content to write to the file.\",\"type\":\"string\"},\"path\":{\"description\":\"Path to the file to write (relative or absolute).\",\"type\":\"string\"}},\"required\":[\"content\",\"path\"],\"type\":\"object\"}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"status":"known","value":true},"name":{"truncated":false,"value":"write"},"ordinal":10,"provenance":{"status":"known","value":"builtin"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"reason":"request field absent","status":"unknown"},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":true,"value":"Run a JavaScript program that composes tool calls with `await tools.call(name, args)` and returns a bounded JSON result. Prefer it whenever you would make several dependent or repetitive calls, MCP and plugin tools included: intermediate results stay in the program and only what you return reaches the conversation. Every nested call passes the same permission checks as a direct call; a call that needs approval pauses the program until the user decides, and a denied or refused call throws inside the program "},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\",\"description\":\"JavaScript program. The return value (or thrown error) becomes the result; use tools.call(name, argsObject) for tool calls.\"}},\"required\":[\"code\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"execute_tools"},"ordinal":11,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"execute_tools_20260918"}},"visibility":"active"},{"allowed_callers":{"status":"known","value":{"count":1,"omitted":0,"rendered":[{"truncated":false,"value":"direct"}]}},"approval":{"reason":"tool is not in the registry","status":"unknown"},"cache_control_type":{"reason":"request field absent","status":"unknown"},"capabilities":{"reason":"tool is not in the registry","status":"unknown"},"defer_loading":{"status":"known","value":false},"description":{"truncated":false,"value":"Search deferred tool definitions and return matching tool references."},"input_examples":{"reason":"request field absent","status":"unknown"},"input_schema_json":{"truncated":false,"value":"{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"Search query for tool discovery.\"},\"match\":{\"type\":\"string\",\"enum\":[\"bm25\",\"regex\"],\"default\":\"bm25\",\"description\":\"Matching algorithm: bm25 for natural-language matching, regex for a regular expression over tool names/descriptions/schema.\"},\"max_results\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":8,\"default\":8,\"description\":\"Maximum number of matching tool references to return.\"}},\"required\":[\"query\"]}"},"mcp_server":{"reason":"the MCP pool did not attribute this tool name","status":"unknown"},"model_visible":{"reason":"tool is not in the registry","status":"unknown"},"name":{"truncated":false,"value":"tool_search"},"ordinal":12,"provenance":{"status":"known","value":"synthetic"},"strict":{"reason":"request field absent","status":"unknown"},"tool_type":{"status":"known","value":{"truncated":false,"value":"tool_search_20251119"}},"visibility":"active"}],"tools_field_present":true,"turn_id":{"truncated":false,"value":""},"unavailable_for_this_request":["provider_wire_payload"]}} {"error":"Model not exist.","event":"turn_complete","parent_route_usage":{"input_tokens":120,"output_tokens":0},"routed_usage_dropped_records":0,"status":"failed","tool_catalog":"","usage":{"input_tokens":120,"output_tokens":0}} -{"harness_summary":{"model_requests":1,"non_streaming_requests":0,"workspace_after":{".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} +{"harness_summary":{"model_requests":1,"non_streaming_requests":0,"workspace_after":{".codewhale/state/.gitignore":"cdbcae15105d6b78",".codewhale/state/subagents.v1.lock":"e3b0c44298fc1c14","NOTES.md":"f957b19529906961","README.md":"41f49bffb38de5ba"}}} diff --git a/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.golden.json b/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.golden.json index 5eeee4f62f..324642d80e 100644 --- a/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.golden.json +++ b/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.golden.json @@ -2,8 +2,8 @@ "system_sha256": "8ff744b8ed90564a8c4754ac79cdbaf05df69ed024cc2ec154abfe581ed72d7f", "system_bytes": 9183, "system_blocks": 5, - "tools_sha256": "6f1ab6f7a2f04bcf68a6e8626e97c816b560ae103e94d7642f4cd5bd9a65ab5e", - "tools_bytes": 14890, + "tools_sha256": "157b468336034c773a179ceb07859a3bf5a93a7829dc5e66ccc0e4902622d9bb", + "tools_bytes": 14897, "tool_count": 12, "tool_names": [ "bash", @@ -19,7 +19,7 @@ "execute_tools", "tool_search" ], - "prefix_sha256": "387edcedb4400d61f81c294eef4e4ed2d3d3ccec07224da128c3547873356260", + "prefix_sha256": "3236f11da18b12c2961510681f0991a95ab4e7e33e6df6fb2785f8685d60ae42", "masks": [ "", "", diff --git a/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.tools.golden.json b/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.tools.golden.json index 44f9d559ae..4b314d1368 100644 --- a/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.tools.golden.json +++ b/crates/tui/tests/fixtures/conformance/prompt/agent_suggest.tools.golden.json @@ -283,7 +283,7 @@ }, "progress": { "additionalProperties": false, - "description": "Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", + "description": "Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", "properties": { "next": { "description": "One short line: what comes next.", diff --git a/crates/tui/tests/fixtures/conformance/prompt/plan_mode.golden.json b/crates/tui/tests/fixtures/conformance/prompt/plan_mode.golden.json index a7b4ea0722..3bb4378ad4 100644 --- a/crates/tui/tests/fixtures/conformance/prompt/plan_mode.golden.json +++ b/crates/tui/tests/fixtures/conformance/prompt/plan_mode.golden.json @@ -2,8 +2,8 @@ "system_sha256": "8ff744b8ed90564a8c4754ac79cdbaf05df69ed024cc2ec154abfe581ed72d7f", "system_bytes": 9183, "system_blocks": 5, - "tools_sha256": "50c90f2a5678c770190f12690cd9793f7c999f0b2a8013e71a43e61f03191fd0", - "tools_bytes": 13360, + "tools_sha256": "91d0b0a9b35665dc0d9e7811d5ed139e7dc761bb49f17acaff757675e27e372c", + "tools_bytes": 13367, "tool_count": 11, "tool_names": [ "bash", @@ -18,7 +18,7 @@ "write", "tool_search" ], - "prefix_sha256": "e4c70ccf568cd9720d7bab82cd0d9c9e446474c2a23c2db370d113551a4fad34", + "prefix_sha256": "6673c1a81b34efa2d5c2a8541c7f0590d7e0dc158d11ad06fcc6b9e848b621c0", "masks": [ "", "", diff --git a/crates/tui/tests/fixtures/conformance/prompt/plan_mode.tools.golden.json b/crates/tui/tests/fixtures/conformance/prompt/plan_mode.tools.golden.json index 58eb635973..76d7830911 100644 --- a/crates/tui/tests/fixtures/conformance/prompt/plan_mode.tools.golden.json +++ b/crates/tui/tests/fixtures/conformance/prompt/plan_mode.tools.golden.json @@ -283,7 +283,7 @@ }, "progress": { "additionalProperties": false, - "description": "Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", + "description": "Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", "properties": { "next": { "description": "One short line: what comes next.", diff --git a/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.golden.json b/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.golden.json index d7262c4944..90d405174e 100644 --- a/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.golden.json +++ b/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.golden.json @@ -2,8 +2,8 @@ "system_sha256": "cd367daa552060c0b30a60263a509fdd25a0d92c89f24aa9f69c174d52076f3d", "system_bytes": 8757, "system_blocks": 5, - "tools_sha256": "6f1ab6f7a2f04bcf68a6e8626e97c816b560ae103e94d7642f4cd5bd9a65ab5e", - "tools_bytes": 14890, + "tools_sha256": "157b468336034c773a179ceb07859a3bf5a93a7829dc5e66ccc0e4902622d9bb", + "tools_bytes": 14897, "tool_count": 12, "tool_names": [ "bash", @@ -19,7 +19,7 @@ "execute_tools", "tool_search" ], - "prefix_sha256": "57bd2508a57eea1011da97e0102b21a549ef7b49267f800400d18a2a7c304745", + "prefix_sha256": "54e30b4850ca16509f2e8fb4b5cbc5eccca33d4802970f1314a6e9d716ea9aa6", "masks": [ "", "", diff --git a/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.tools.golden.json b/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.tools.golden.json index 44f9d559ae..4b314d1368 100644 --- a/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.tools.golden.json +++ b/crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.tools.golden.json @@ -283,7 +283,7 @@ }, "progress": { "additionalProperties": false, - "description": "Optional with not_achieved or advisory: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", + "description": "Optional with not_achieved, advisory or yield: your current best estimate of overall completion, shown to the user as reported progress. Keep percent honest — it is an estimate, never a verified fraction.", "properties": { "next": { "description": "One short line: what comes next.", diff --git a/docs/BUILD_PERFORMANCE.md b/docs/BUILD_PERFORMANCE.md index 3f0aa739a3..4b1ea29b22 100644 --- a/docs/BUILD_PERFORMANCE.md +++ b/docs/BUILD_PERFORMANCE.md @@ -210,10 +210,12 @@ every workspace crate. ### A2 nextest in CI -`cargo test --workspace --all-features --locked --doc` inventories -**3 passing / 8 ignored doctests across 21 crates**; CI keeps them as a -separate step next to `cargo nextest run --workspace --all-features ---locked --profile ci`. +`cargo test --workspace --all-features --locked --doc` inventoried +**3 passing / 8 ignored doctests across 21 crates**. All 8 ignored fences +were in codewhale-tui, which has no runnable doc example and now sets +`doctest = false`, so its doc pass is skipped (the new inventory is not +re-measured yet). CI keeps the doc run as a separate step next to +`cargo nextest run --workspace --all-features --locked --profile ci`. ### A3/A4 (not adopted, measured) diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index ce1c3ca729..d7f482ede7 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -77,7 +77,7 @@ required first-run screen. Customize it later through `/constitution` or the progressive `/setup` guide. Provider/model readiness, workspace trust, and runtime posture stay separate from this guidance. -On the **Constitution** step: +On the **Working agreement** (constitution) step: - **`1`–`6`** tune the guided draft. **`G`** previews it, and **`G`** again ratifies and saves a fresh structured `constitution.json`. @@ -91,8 +91,9 @@ On the **Constitution** step: `/constitution` (alias `/law`) is the primary management surface once you are set up. Subcommands: `status` (the default), `preview`, `review`, `repo` (the -repo-local law block), `explain`, `edit`/`guided`, `repair`, `posture`, and -`bundled`. Managing the constitution never changes runtime approval, sandbox, +repo-local law block), `explain`, `base`, `suggestions`, `ratify `, +`migrate`, `rollback`, `edit`/`guided`, `repair`, `posture`, and `bundled`. +Managing the constitution never changes runtime approval, sandbox, shell, network, trust, default mode, or MCP authority — those stay in runtime posture/config. diff --git a/docs/CONTRIBUTORS.md b/docs/CONTRIBUTORS.md index 26e5c12167..7cef2ea3bd 100644 --- a/docs/CONTRIBUTORS.md +++ b/docs/CONTRIBUTORS.md @@ -39,10 +39,11 @@ changelog or release notes, and this contributor record. **Contributions** -- **[Sh1Zuku / SparkofSpike](https://github.com/SparkofSpike)** — live network-policy updates and goal milestone hand-back ([#6928](https://github.com/codewhale-hq/Codewhale/pull/6928), [#6930](https://github.com/codewhale-hq/Codewhale/pull/6930)). +- **[Sh1Zuku / SparkofSpike](https://github.com/SparkofSpike)** — live network-policy updates and goal milestone hand-back ([#6928](https://github.com/codewhale-hq/Codewhale/pull/6928), [#6930](https://github.com/codewhale-hq/Codewhale/pull/6930)), and a Codewhale home reached through a symlink or junction ([#6947](https://github.com/codewhale-hq/Codewhale/issues/6947)). - **[dajiaohuang](https://github.com/dajiaohuang)** — cache-write token accounting, with missing and explicit-zero usage preserved ([#6913](https://github.com/codewhale-hq/Codewhale/pull/6913)). - **[gaord](https://github.com/gaord)** — embedder-declared telemetry surface support without changing collection policy ([#6916](https://github.com/codewhale-hq/Codewhale/pull/6916)). -- **[Lstarsky0](https://github.com/Lstarsky0)** — localized `/profile` replies across all 15 complete locale packs ([#6919](https://github.com/codewhale-hq/Codewhale/pull/6919)). +- **[Lstarsky0](https://github.com/Lstarsky0)** — localized `/profile` replies across all 15 complete locale packs ([#6919](https://github.com/codewhale-hq/Codewhale/pull/6919)), and workflow gates that block their own role rejected at plan admission ([#6952](https://github.com/codewhale-hq/Codewhale/pull/6952)). +- **[LIghtJUNction](https://github.com/LIghtJUNction)** — plugin shell install and in-TUI plugin OAuth sign-in with `/connect` and `/disconnect` ([#6950](https://github.com/codewhale-hq/Codewhale/pull/6950)). - **[jayanthvee](https://github.com/jayanthvee)** — Windows npm launcher guidance and targeted process shutdown ([#6906](https://github.com/codewhale-hq/Codewhale/pull/6906)). - **[asto18089](https://github.com/asto18089)** — reference fix for longer browser sign-in callback windows ([#6865](https://github.com/codewhale-hq/Codewhale/issues/6865)). diff --git a/docs/GUIDE.md b/docs/GUIDE.md index 9a862edb71..d56c73d135 100644 --- a/docs/GUIDE.md +++ b/docs/GUIDE.md @@ -94,7 +94,7 @@ server answers. The provider step also has an explicit offline route. Everything optional stays available after that. Use `/setup` for the progressive setup and repair guide, `/settings` for the full typed editor, and -`/constitution` when you want to customize the bundled working agreement. +`/constitution` when you want your own constitution on top of the bundled one. The localized telemetry choice appears only after the workspace is ready and does not block the composer. diff --git a/docs/SUBAGENTS.md b/docs/SUBAGENTS.md index 751bf017f1..0433296db4 100644 --- a/docs/SUBAGENTS.md +++ b/docs/SUBAGENTS.md @@ -160,9 +160,9 @@ turn is included. **The list is shown once, at that spawn, and never re-sent.** No sub-agent request re-states a To-do list, and neither does a parent request. Each agent -keeps its own private list (#4810); what it knows about that list comes from the -tool results its own `todo_write` calls returned, which are ordinary messages in -its own transcript. A worker therefore cannot read or write a parent's or a +keeps its own private list (#4810); what it knows about that list comes from its +own `todo_write` calls (each sends the whole list) and the short receipts they +returned, which are ordinary messages in its own transcript. A worker therefore cannot read or write a parent's or a sibling's list, and a forked child cannot mutate the snapshot it was handed or keep reading later parent changes. diff --git a/docs/TOOL_LIFECYCLE.md b/docs/TOOL_LIFECYCLE.md index 0ee9adaa8e..31ef8f73b5 100644 --- a/docs/TOOL_LIFECYCLE.md +++ b/docs/TOOL_LIFECYCLE.md @@ -88,8 +88,9 @@ not a progress surface, must not duplicate To-do items, and plan-only state is never rendered as a To-do snapshot. **No request re-states the list.** The model learns what is on the To-do the way -it learns anything else: from the result its own `todo_write` call returned, -which is ordinary persisted history. Nothing is appended to a parent turn-loop +it learns anything else: from its own `todo_write` call, whose input is the +whole list, and the short receipt it returned (counts and the item in +progress). Both are ordinary persisted history. Nothing is appended to a parent turn-loop step or a sub-agent step. The complete list stays visible in the UI, which is a different surface from the request. diff --git a/docs/design/DECONSTRUCTION_ROADMAP.md b/docs/design/DECONSTRUCTION_ROADMAP.md index f829f93868..b210db32c8 100644 --- a/docs/design/DECONSTRUCTION_ROADMAP.md +++ b/docs/design/DECONSTRUCTION_ROADMAP.md @@ -22,7 +22,7 @@ to a date: at the observed cadence (0.10.0 on 2026-09-22, 0.10.1 on - Test edges and test code are not in the tarball: tests/**, **/tests.rs, **/tests/**, *_tests.rs and test_cases_*.rs are excluded by crates/tui/Cargo.toml. Moving tests therefore frees 0 bytes of tarball. Inline `#[cfg(test)]` blocks in non-excluded files (schema_sanitize.rs from line 470, settings.rs from line 2372, test_support.rs from line 657) do ship. - Cadence is the unmeasured cost. v0.10.0 is dated 2026-09-22 and v0.10.1 2026-10-07 (15 days, measured from tags). The sequencer's 10 patch releases to 0.11.0 is about five months at that rate, with no calendar stated. The shared prefix here is 0.10.2 to 0.10.5, roughly six weeks. Track B items are explicit, optional and uncalendared. - Never widen a trust boundary silently. Every `pub(crate)` to `pub` change (try_lock_file_exclusive, test-support items, execpolicy rule types, credentials) gets a one-paragraph visibility review in the commit message. -- Release-time human gates stay human: tags, crates.io upload, new package names, the publication of codewhale-ratatui. tui's manifest depends on crates.io codewhale-ratatui 0.1.1, which is excluded from the workspace and is not in crates.sh or check-crate-sizes.py. It must already be published before any dry-run or upload that builds tui from a tarball. +- Release-time human gates stay human: tags, crates.io upload, new package names, the publication of codewhale-ratatui. tui's manifest depends on crates.io codewhale-ratatui 0.1.2, which is excluded from the workspace and is not in crates.sh or check-crate-sizes.py. It must already be published before any dry-run or upload that builds tui from a tarball. ## Releases @@ -31,11 +31,11 @@ to a date: at the observed cadence (0.10.0 on 2026-09-22, 0.10.1 on Slices: - Release the stamped candidate. workspace.version is already 0.10.2 in Cargo.toml, and `wip(0.10.2)` and ratatui-0.1.1 release-prep commits are on main. The working tree has 48 dirty entries (CHANGELOG.md, settings.rs, tui/app*, runtime_api/*, core/authority.rs, a staged deletion of full_access_confirm.rs). A structural move on top of an RC with another agent's feature in flight is the largest avoidable risk in the plan. - Non-move rider: write the real per-crate tarball sizes (from the dry-run's check-crate-sizes.py output) into the release notes table. This is the baseline column for every later release. -- Non-move rider: record the codewhale-ratatui 0.1.1 publication receipt in the release notes (out-of-band crate, not in crates.sh). +- Non-move rider: record the codewhale-ratatui 0.1.2 publication receipt in the release notes (out-of-band crate, not in crates.sh). -- **Entry gate:** Founder-owned release process per docs/RELEASE_RUNBOOK.md. `python3 scripts/split/module_graph.py --check` PASS at 11/35/1/1. codewhale-ratatui 0.1.1 is on crates.io (human gate). The dirty full-access and settings work is either in the candidate or excluded by its owner. +- **Entry gate:** Founder-owned release process per docs/RELEASE_RUNBOOK.md. `python3 scripts/split/module_graph.py --check` PASS at 11/32/1/1. codewhale-ratatui 0.1.2 is on crates.io (human gate). The dirty full-access and settings work is either in the candidate or excluded by its owner. - **Exit gate:** `./scripts/release/publish-crates.sh dry-run` passes for all 29 crates, including check-crate-sizes.py. validate-crate-publish-order.py passes. Hosted CI green on the exact SHA (macOS and Windows jobs). Source, local, CI, packaged-artifact and release-state evidence are reported separately. -- **Ratchet target:** unchanged: prod 11, test 35, late 1, uilib 1. +- **Ratchet target:** prod 11, test 32 (RS-12 cleared fleet|lib.rs 3), late 1, uilib 1. - **Size budget:** All 29 crates: no growth versus the recorded table. codewhale-tui about 9.47 MiB real (about 9.50 by proxy). Not a gate on structure. - **Risks:** Carrying a structural move into the candidate would collide with the dirty tree. Nothing to roll back structurally. - **Rollback:** Normal release rollback per the runbook. No structural change to revert. @@ -47,9 +47,9 @@ Slices: - Design-doc correction the sequencer dropped: install the real catalog process-wide for tests. A thread-local guard cannot reach the Runtime API test server thread. - Riders (no graph change): cut `runtime_api|commands` test edges (2) in the same files; move `late` (test_cases_04.rs:1197) and `uilib` (roster_routes.rs:798) test edges only if the owning test files are not dirty. -- **Entry gate:** module_graph.py --check PASS at 11/35/1/1. The files this slice edits are clean in `git status`: runtime_api.rs (13,649 lines, not dirty now), tools/tui_help.rs, commands/catalog.rs, extension_host/command.rs. The sequencer's 'clean in all of commands/ and runtime_api/' would block this slice today, since runtime_api/tests.rs, runtime_api/thread_history.rs and commands/groups/config/config.rs are dirty. Require only the exact files edited, and coordinate on runtime_api/tests.rs if the test guard install touches it. One named build owner. +- **Entry gate:** module_graph.py --check PASS at 11/32/1/1. The files this slice edits are clean in `git status`: runtime_api.rs (13,649 lines, not dirty now), tools/tui_help.rs, commands/catalog.rs, extension_host/command.rs. The sequencer's 'clean in all of commands/ and runtime_api/' would block this slice today, since runtime_api/tests.rs, runtime_api/thread_history.rs and commands/groups/config/config.rs are dirty. Require only the exact files edited, and coordinate on runtime_api/tests.rs if the test guard install touches it. One named build owner. - **Exit gate:** Slice gate: ratchet --check at prod 0 with the baseline JSON updated in the same commit. cargo fmt --check. clippy with CI's flags. `scripts/dev-test.sh` runtime_api and commands filters with N > 0 passed, including a slash-command-list API test and the /help test. Journey on the built binary: slash palette lists commands, /help, GET of the runtime API command list. Release gate at cut: publish-crates.sh dry-run and green hosted CI on the SHA. -- **Ratchet target:** prod 11 -> 0, test 35 -> 33 (runtime_api|commands 2 cleared if achieved), late 1, uilib 1. Design doc predicts the cycle 100 -> 83 modules; re-run partition_report.py and quote the real number. +- **Ratchet target:** prod 11 -> 0, test 32 -> 30 (runtime_api|commands 2 cleared if achieved), late 1, uilib 1. Design doc predicts the cycle 100 -> 83 modules; re-run partition_report.py and quote the real number. - **Size budget:** No crate grows. A new leaf module in tui adds a few KiB. - **Risks:** Highest churn path: runtime_api is 286 commits in 30 days. The port could be built as a second registry (guard by deleting callers). The catalog process-wide install can leak between tests. - **Rollback:** Annotated local recovery tag plus a CW/backups note. `git revert` of the slice commit on main. No reset, no force-push. If 0.10.3 is already cut, fix forward before any other move. @@ -71,10 +71,10 @@ Slices: ### 0.10.5: Test-edge rehoming and the A/B decision release. Non-graph cleanup, no crate moves. Slices: -- Rehome the remaining test edges so no #[cfg(test)] code in the runtime half names crate::tui, commands or lib.rs: tools|tui 12, client|tui 3, session_manager|tui 3, fleet|lib.rs 3, config|tui 2, core|tui 2, prompts|tui 1, plus late 1 and uilib 1. Mechanism: move each such test to a tui-side integration module or replace the tui fixture with a runtime-side one. Split across several landings on main, owned per directory. +- Rehome the remaining test edges so no #[cfg(test)] code in the runtime half names crate::tui, commands or lib.rs: tools|tui 12, client|tui 3, session_manager|tui 3, config|tui 2, core|tui 2, prompts|tui 1, plus late 1 and uilib 1. Mechanism: move each such test to a tui-side integration module or replace the tui fixture with a runtime-side one. Split across several landings on main, owned per directory. - Record the founder's A/B decision (open_decisions[0]) before any Track B release starts. -- **Entry gate:** 0.10.4 shipped. Per-landing: the test files edited are not dirty. Mapping of the 35 edges to files regenerated with `module_graph.py --report` at the start of the release and posted in the Linear issue. +- **Entry gate:** 0.10.4 shipped. Per-landing: the test files edited are not dirty. Mapping of the 32 edges to files regenerated with `module_graph.py --report` at the start of the release and posted in the Linear issue. - **Exit gate:** module_graph.py --check at prod 0, test 0, late 0, uilib 0, baseline JSON updated. Existing tests for each touched file run with identical pass counts (quote before and after). No production file changed except visibility needed by a moved fixture. The A/B decision is recorded in docs/design/TUI_DECONSTRUCTION.md. - **Ratchet target:** prod 0, test 33 -> 0, late 1 -> 0, uilib 1 -> 0. - **Size budget:** No change. Test files are excluded from the tarball. @@ -191,7 +191,7 @@ Slices: Slices: - Option A (RS-14, #6941): after 0.10.5, move the remaining runtime half into one new crate with scripts/split/move-modules.py, everything except src/tui, src/commands, composer_*, model_relevance and config_keys; codewhale-tui stays the UI plus composition root. Proxy sizes: UI 2.78 MiB (435 files), runtime remainder 6.89 MiB (714 files, of which extension-host, plugins and assets 1.16 MiB). The sequencer's 2.7 / 6.7 estimates are within 0.2 MiB. - Compatibility event, corrected: crates/cli uses codewhale_tui::run (11 uses), RuntimeOptions (8 uses, ::default and the type), route_preferences (get, is_route_key, set_document, set, selected_route, unset, scrub_root_model_aliases_for_export), config_keys (resolved_stream_config, unread_config_keys, config_key_home) and set_telemetry_preference. The sequencer's list omitted RuntimeOptions and set_telemetry_preference. Keep all re-exported from codewhale-tui. -- Publish impact: crates.sh goes 29 -> 30 (new crate placed after core, config, models, runtime, before tui). codewhale-ratatui 0.1.1 stays out of band, so 'all 30 crates' is 30 plus ratatui. +- Publish impact: crates.sh goes 29 -> 30 (new crate placed after core, config, models, runtime, before tui). codewhale-ratatui 0.1.2 stays out of band, so 'all 30 crates' is 30 plus ratatui. - Option B (founder declines RS-14): continue Track B items and then config-types sections one per release. tui stays about 9.5 MiB and the cap stays the binding constraint. - **Entry gate:** Option A: 0.10.2 to 0.10.5 shipped. Ratchet reads prod 0, test 0, late 0, uilib 0. Founder A/B decision recorded and new crate name approved (human gate). Frozen write window across the workspace and one build owner (a new crate adds a build cache: df -h /Volumes/VIXinSSD first). Dirty tree empty for crates/tui. Option B: Track B through 0.10.15 shipped. @@ -203,7 +203,7 @@ Slices: ## Measurement plan -Record at every release, on one machine, at a named source commit with a dirty-file inventory. Numbers from a tree that changed during the compile are void. (1) Tarball sizes: the real sizes from the release dry-run's check-crate-sizes.py output for all published crates, in a table with the previous release's value and the delta. Between releases use the proxy, run from crates/tui: `git ls-files . | grep -vE '^tests/|/tests\.rs$|/tests/|_tests\.rs$|/test_cases_[^/]*\.rs$|^extension-host/test/|^plugins/computer-use/tests/' | tar -czf /tmp/x.tgz -T -`. It read 9.50 MiB for HEAD against 9.47 real, so it is good to about 0.03 MiB. Anything smaller than 0.03 MiB is not measurable, so no per-slice size budgets below that. Mark each cell proxy or real. (2) `python3 scripts/split/module_graph.py --check` four counts plus the closure-module count, committed as the baseline in the same commit as the move. Today: prod 11, test 35, late 1, uilib 1, 117 modules. (3) Build timing via scripts/dev-cargo.sh after `df -h /Volumes/VIXinSSD`: cold `cargo test -p codewhale-tui --lib --locked --no-run --timings`; warm touch-one-file loops; a loop touching a file inside the moved code; peak RSS via /usr/bin/time -l; three runs, median and spread. Baseline from docs/BUILD_PERFORMANCE.md: cold 94 s for `cargo build -p codewhale-tui`, about 12.5 s incremental build and about 20 s lib-test. No speedup is claimed for any leaf move (each is under 1% of the closure). Only Option A can plausibly change build time, and it is not measured until run. (4) nextest wall time and real 'N passed' per affected crate (N > 0), quoting before and after for every relocated test. (5) Hosted CI job durations for macOS and Windows on the exact SHA. Windows-only cfg code (test-support tempdir, credentials ACLs, fd-lock paths) cannot be proven locally. (6) Churn: `git log --since=30.days` per moved path. Today runtime_api is 286, runtime_threads 169, tools/subagent 226, settings.rs 16, core/events.rs 27. Use it to schedule landings, not to justify moves. (7) Release cadence: days between tags (v0.10.0 to v0.10.1 was 15 days) recorded per release to keep the calendar honest. (8) One table row per release in docs/design/TUI_DECONSTRUCTION.md, each cell marked measured, proxy or not measured. +Record at every release, on one machine, at a named source commit with a dirty-file inventory. Numbers from a tree that changed during the compile are void. (1) Tarball sizes: the real sizes from the release dry-run's check-crate-sizes.py output for all published crates, in a table with the previous release's value and the delta. Between releases use the proxy, run from crates/tui: `git ls-files . | grep -vE '^tests/|/tests\.rs$|/tests/|_tests\.rs$|/test_cases_[^/]*\.rs$|^extension-host/test/|^plugins/computer-use/tests/' | tar -czf /tmp/x.tgz -T -`. It read 9.50 MiB for HEAD against 9.47 real, so it is good to about 0.03 MiB. Anything smaller than 0.03 MiB is not measurable, so no per-slice size budgets below that. Mark each cell proxy or real. (2) `python3 scripts/split/module_graph.py --check` four counts plus the closure-module count, committed as the baseline in the same commit as the move. Today: prod 11, test 32, late 1, uilib 1, 117 modules. (3) Build timing via scripts/dev-cargo.sh after `df -h /Volumes/VIXinSSD`: cold `cargo test -p codewhale-tui --lib --locked --no-run --timings`; warm touch-one-file loops; a loop touching a file inside the moved code; peak RSS via /usr/bin/time -l; three runs, median and spread. Baseline from docs/BUILD_PERFORMANCE.md: cold 94 s for `cargo build -p codewhale-tui`, about 12.5 s incremental build and about 20 s lib-test. No speedup is claimed for any leaf move (each is under 1% of the closure). Only Option A can plausibly change build time, and it is not measured until run. (4) nextest wall time and real 'N passed' per affected crate (N > 0), quoting before and after for every relocated test. (5) Hosted CI job durations for macOS and Windows on the exact SHA. Windows-only cfg code (test-support tempdir, credentials ACLs, fd-lock paths) cannot be proven locally. (6) Churn: `git log --since=30.days` per moved path. Today runtime_api is 286, runtime_threads 169, tools/subagent 226, settings.rs 16, core/events.rs 27. Use it to schedule landings, not to justify moves. (7) Release cadence: days between tags (v0.10.0 to v0.10.1 was 15 days) recorded per release to keep the calendar honest. (8) One table row per release in docs/design/TUI_DECONSTRUCTION.md, each cell marked measured, proxy or not measured. ## Coordination rules (shared checkout) @@ -230,7 +230,7 @@ Record at every release, on one machine, at a named source commit with a dirty-f - CHANGED: settings S1: production is 2,372 lines (first cfg(test) at settings.rs:2372), not about 2.9k, and the file imports pricing, so it stays blocked on #6396 for CostCurrency. Moved to the end of Track B (0.10.15). - CHANGED: X1 scope: the move must also take RuntimeProcessOwnerLock::try_lock_exclusive and is_contention (runtime_threads.rs:6855). The sequencer described a pure rename of the free function (runtime_threads.rs:6592) that calls both. Verified production call sites: session_manager.rs:1823, 1879, 1954 and session_reconcile.rs:256; the other five are tests. Marked seam-introducing, not pure rename. - CHANGED: size gates. Removed the per-slice size_budget numbers (9.44, 9.43, 9.42, 9.38, 9.36, 9.34, 9.30) and the per-slice `cargo package` + check-crate-sizes gate. They sit below proxy resolution (about 0.03 MiB) and a single-crate `cargo package` cannot resolve unpublished 0.10.x workspace deps; only the multi-package dry-run can, and it builds all 29 tarballs. Replaced with: no crate grows at the release cut, plus one proxy command for between-release checks. Size-guard question for the founder: keep the 10 MiB hard fail unchanged (recommended); decide whether the fixed 90% warn becomes relative to the last release's recorded size. The warn fires on codewhale-tui every release at 94.7% and is the only noise. Not changed by this plan, and I recommend leaving the script alone until the table of real sizes exists. -- CHANGED: publish-side facts. codewhale-ratatui 0.1.1 is a published dependency of tui that is neither in crates.sh nor checked by check-crate-sizes.py (vendor/codewhale-ratatui is a workspace exclude; check-versions.sh special-cases it). It must be on crates.io before any dry-run that unpacks tui. Added to the 0.10.2 entry gate and to the 0.11.0 'all 30 crates' wording. Founder to confirm that its size is intentionally outside the guard. +- CHANGED: publish-side facts. codewhale-ratatui 0.1.2 is a published dependency of tui that is neither in crates.sh nor checked by check-crate-sizes.py (vendor/codewhale-ratatui is a workspace exclude; check-versions.sh special-cases it). It must be on crates.io before any dry-run that unpacks tui. Added to the 0.10.2 entry gate and to the 0.11.0 'all 30 crates' wording. Founder to confirm that its size is intentionally outside the guard. - CHANGED: coordination. Added pathspec commits. Verified `D crates/tui/src/tui/full_access_confirm.rs` is already staged by another agent, so 'stage only owned paths' is not enough if the commit takes the whole index. Replaced the blanket 'dirty tree blocks the slice' with a named-files rule and a skip-to-next-independent-release rule. - CHANGED: 0.11.0 compatibility list: crates/cli also uses RuntimeOptions (8 uses) and set_telemetry_preference. Proxy sizes validate the sequencer's Option A estimate within 0.2 MiB (UI 2.78 vs 2.7, runtime 6.89 vs 6.7); the budget is raised to 7.2 MiB so a measured 6.89 plus growth does not trip it. - NOT RE-VERIFIED: X7's exact moved set (design table says tool_denied, tool_matches_any_rule, requires_raw_shell, policy_tool_aliases; sequencer says AutoReview* types and HumanDecision), the 9.47 MiB real tarball (only the proxy 9.50 was computed), live state of #6937-#6941, the 12/55/30/62 edge counts in the sequencer's ratchet targets, the 29-crate dry-run build time, any build-time effect. @@ -240,10 +240,10 @@ Record at every release, on one machine, at a named source commit with a dirty-f ## Tracking issues to file (one per slice) - **0.10.5**: A/B decision: RS-14 atomic move vs slice-only path (record in 0.10.5). Decide whether 0.11.0 is the atomic move of the remaining runtime SCC (Option A) or the design doc's slice-only path (Option B). Evidence: with A, X1/X4/X7/X8/P1/P2/settings are not prerequisites; only A moves tui below 9.0 MiB (proxy UI 2.78 MiB / runtime 6.89 MiB). Needs prod/test/late/uilib all 0 first. Linear only, not mirrored. Reuse the #6941 issue if it covers this. -- **0.10.2**: 0.10.2: ship candidate with no structural move; record per-crate tarball table and ratatui 0.1.1 receipt. No move in the candidate. Add real per-crate tarball sizes to the release notes (baseline for later releases) and the codewhale-ratatui 0.1.1 publication receipt (out of band, not in crates.sh). Gate: publish-crates.sh dry-run, validate-crate-publish-order.py, hosted CI green on the SHA. +- **0.10.2**: 0.10.2: ship candidate with no structural move; record per-crate tarball table and ratatui 0.1.2 receipt. No move in the candidate. Add real per-crate tarball sizes to the release notes (baseline for later releases) and the codewhale-ratatui 0.1.2 publication receipt (out of band, not in crates.sh). Gate: publish-crates.sh dry-run, validate-crate-publish-order.py, hosted CI green on the SHA. - **0.10.3**: 0.10.3 X2: command catalog port, finish RS-13 (#6940). runtime_api.rs:4815-4898 and tools/tui_help.rs go through a command_catalog leaf; delete the direct call sites; install the real catalog process-wide for tests. Ratchet prod 11 -> 0. Claim exact files only (runtime_api.rs, tools/tui_help.rs, commands/catalog.rs, extension_host/command.rs). Linear only, not mirrored. - **0.10.4**: 0.10.4 W0-S2: codewhale-test-support (publish=false), env half. Move test_env_lock.rs (300) and the env half of test_support.rs (657 non-test lines) to crates/test/test-support; version.workspace=true; add to root members; keep tui shim and App fixtures; remove shell_dispatcher cfg(test) mount and the tests/integration #[path] include. Critical path for settings and credentials tests. Gate: equal before/after pass counts, one process-global lock copy, crates.sh stays 29. -- **0.10.5**: 0.10.5 Test-edge rehoming: test 35 -> 0, late 1 -> 0, uilib 1 -> 0. Rehome tests naming crate::tui, commands or lib.rs (tools|tui 12, client|tui 3, session_manager|tui 3, fleet|lib.rs 3, config|tui 2, core|tui 2, prompts|tui 1), plus test_cases_04.rs:1197 (exec_agent) and roster_routes.rs:798 (crossterm). Test-only; equal pass counts before and after per directory. Prerequisite for any new runtime crate that must not depend on tui or crossterm. +- **0.10.5**: 0.10.5 Test-edge rehoming: test 32 -> 0, late 1 -> 0, uilib 1 -> 0. Rehome tests naming crate::tui, commands or lib.rs (tools|tui 12, client|tui 3, session_manager|tui 3, config|tui 2, core|tui 2, prompts|tui 1), plus test_cases_04.rs:1197 (exec_agent) and roster_routes.rs:798 (crossterm). Test-only; equal pass counts before and after per directory. Prerequisite for any new runtime crate that must not depend on tui or crossterm. - **0.10.6**: 0.10.6 X1 [Track B]: fslock into crates/runtime. Move try_lock_file_exclusive plus RuntimeProcessOwnerLock::try_lock_exclusive/is_contention (runtime_threads.rs:6592, 6855) to crates/runtime. Seam-introducing, not pure rename. Blocked until runtime_threads.rs and its tests are committed. Visibility review in the commit message; revert immediately on any lock regression. - **0.10.7**: 0.10.7 X7 [Track B]: tool rules into execpolicy. Reconcile the moved set (design table: tool_denied, tool_matches_any_rule, requires_raw_shell, policy_tool_aliases; AutoReviewPolicy lives in core/authority/auto_review) then move to crates/execpolicy with re-exports. Approval trust boundary: no matching or visibility change. Blocked by dirty core/authority.rs. - **0.10.8**: 0.10.8 X4 [Track B]: schema_sanitize/schema_canonicalize production half into codewhale-models. Move schema_sanitize.rs lines 1-469 and schema_canonicalize.rs to codewhale-models (owns Tool). Tests stay in tui. No new package name. Assert byte-identical sanitized output on existing fixtures (KV-cache prefix). diff --git a/docs/design/TUI_DECONSTRUCTION.md b/docs/design/TUI_DECONSTRUCTION.md index 5f68007344..35d51792b3 100644 --- a/docs/design/TUI_DECONSTRUCTION.md +++ b/docs/design/TUI_DECONSTRUCTION.md @@ -395,7 +395,7 @@ Running them in parallel: tests, `python3 scripts/split/module_graph.py --check` with the counts it should lower, and `python3 scripts/split/partition_report.py` before and after. -Mapping of the open issues: RS-8 (#6935), RS-9 (#6936), RS-12 (#6939, partial) and +Mapping of the open issues: RS-8 (#6935), RS-9 (#6936), RS-12 (#6939) and RS-13 (#6940, first sub-slice) landed; X2 completes RS-13; W0-S1 and W0-S2 replace RS-10 (#6937) and the test-support half of RS-11 (#6938); RS-14 (#6941) is replaced by this table pending the founder's decision. diff --git a/docs/features.toml b/docs/features.toml index 0bdfec3fd2..ef9509085b 100644 --- a/docs/features.toml +++ b/docs/features.toml @@ -682,7 +682,7 @@ owner = "crates/tui/src/oauth.rs" [[feature]] id = "plugin-oauth-providers" name = "Reviewed plugin OAuth providers" -summary = "Reviewed plugins connect with /connect ; the host owns PKCE, model discovery and per-request approvals." +summary = "Reviewed plugins sign in with /connect and out with /disconnect; the host owns PKCE, models and approvals." status = "experimental" surfaces = { tui = "preview", api = "partial", web = "none" } since = "unreleased" diff --git a/docs/zh_hans/SUBAGENTS.md b/docs/zh_hans/SUBAGENTS.md index 6389320c57..3a7a305b7d 100644 --- a/docs/zh_hans/SUBAGENTS.md +++ b/docs/zh_hans/SUBAGENTS.md @@ -56,7 +56,7 @@ Fleet 角色是委派工作面向用户的词汇:父智能体通过 `agent` 分叉状态显示的是父智能体的 To-do 快照——由 `todo_write` 写入的唯一的 Work 界面。子智能体的 `` 块携带 `crates/tui/src/todo_snapshot.rs` 渲染的有界正文,因此分叉是从父智能体真实的进度位置继续,而不是从一段转述继续。这一 To-do 部分在生成发生时解析,所以同一个父回合中更早的 `todo_write` 也会被包含进来。 -**该列表只在生成的那一刻显示一次,之后绝不会重新发送。** 没有哪个子智能体请求会重新陈述 To-do 列表,父智能体的请求也不会。每个智能体都保留自己的私有列表(#4810);它对这个列表的了解,来自它自己的 `todo_write` 调用返回的工具结果,而这些结果是它自己转录中的普通消息。因此 `worker` 无法读取或写入父智能体或兄弟智能体的列表,被分叉出的子智能体也无法修改交给它的快照,或持续读取父智能体之后的变化。 +**该列表只在生成的那一刻显示一次,之后绝不会重新发送。** 没有哪个子智能体请求会重新陈述 To-do 列表,父智能体的请求也不会。每个智能体都保留自己的私有列表(#4810);它对这个列表的了解,来自它自己的 `todo_write` 调用(每次调用都发送完整列表)以及这些调用返回的简短回执,而这些都是它自己转录中的普通消息。因此 `worker` 无法读取或写入父智能体或兄弟智能体的列表,被分叉出的子智能体也无法修改交给它的快照,或持续读取父智能体之后的变化。 子智能体转录内卡片显示的正是这份私有列表。一张委派卡片渲染的是**它自己**那个智能体 To-do 的有界投影——已完成/总数计数、始终包含进行中的条目、最多三行,以及当界限省略其余部分时显式的 `… +N more`——由 `card_todo_projection` 用与面向模型的正文相同的快照、优先级顺序和清洗器构建。卡片只会消费 `agent_id` 与自己匹配的信封,因此父智能体的列表绝不会出现在子智能体名下,也没有兄弟智能体的列表会出现在另一个名下。没有陈述任何工作的智能体完全不显示 To-do 行,而不是显示占位任务;终态卡片保留它的智能体实际发布的最后一份快照。扇出(fanout)卡片保持为圆点网格,不显示子智能体的 To-do:一张卡片背后有许多 `worker` 时,没有一个能如实挂载单一列表的位置。只有当运行时已经把该子智能体表示为它自己的委派卡片时,才会出现子智能体的 To-do。 diff --git a/docs/zh_hans/TOOL_LIFECYCLE.md b/docs/zh_hans/TOOL_LIFECYCLE.md index fe9856ae95..dc4127c10b 100644 --- a/docs/zh_hans/TOOL_LIFECYCLE.md +++ b/docs/zh_hans/TOOL_LIFECYCLE.md @@ -40,7 +40,7 @@ Codewhale 自带庞大的原生工具面。该面的首回合 *active* 分区是 **To-do 是唯一的工作面。** `update_plan` 是对话式推理——面向复杂项目的策略、上下文和路线说明。它不是进度面,不得重复 To-do 条目,仅计划状态永远不会渲染为 To-do 快照。 -**任何请求都不会重述清单。** 模型了解 To-do 上有哪些内容的方式与其他任何信息相同:通过它自己的 `todo_write` 调用返回的结果——那是普通的持久化历史。不会向父回合循环步骤或子智能体步骤追加任何内容。完整清单始终在 UI 中可见,而 UI 是与请求不同的另一个面。 +**任何请求都不会重述清单。** 模型了解 To-do 上有哪些内容的方式与其他任何信息相同:通过它自己的 `todo_write` 调用——调用的输入就是完整清单——以及该调用返回的简短回执(计数和进行中的条目)。两者都是普通的持久化历史。不会向父回合循环步骤或子智能体步骤追加任何内容。完整清单始终在 UI 中可见,而 UI 是与请求不同的另一个面。 `crates/tui/src/todo_snapshot.rs` 渲染那唯一的受限主体——在条目数和字符数上都硬受限,进行中的条目被优先保留,任何省略都被标记——用于三个*一次性*显示快照的接缝,因为是人提出的要求:新分叉的智能体拿到的 `` 块、`/relay` 以及转录内的智能体卡片。 diff --git a/pet/scripts/check-shared.py b/pet/scripts/check-shared.py index 5bb739cf99..6701b39245 100644 --- a/pet/scripts/check-shared.py +++ b/pet/scripts/check-shared.py @@ -90,7 +90,7 @@ def passed(name): checks.append(name);print('PASS '+name,flush=True) request(d,'/v1/audio',{'client':audio_a,'enabled':False}) request(d,'/v1/audio',{'client':audio_b,'enabled':False}) before_style=request(d,'/v1/export') - appearance={'background':[238,239,235],'backgroundTop':[255,255,250],'particle':[32,79,83],'eventColors':False,'brightness':1.4,'dotScale':1.2,'glow':.25,'environment':False} + appearance={'background':[238,239,235],'backgroundTop':[255,255,250],'particle':[32,79,83],'eventColors':False,'brightness':1.4,'dotScale':1.2,'glow':.25,'environment':False,'bodyStyle':'pixel','textLanguage':'ja'} style_action={'identity':d['identity'],'client':str(uuid.uuid4()),'seq':1,'source_revision':b['sourceRevision'],'action':{'kind':'appearance','appearance':appearance}} reject(d,'/v1/action',dict(style_action,action={'kind':'appearance','appearance':dict(appearance,brightness=999)})) request(d,'/v1/action',style_action) diff --git a/pet/tui/Cargo.lock b/pet/tui/Cargo.lock index b02babf380..4128b8aea7 100644 --- a/pet/tui/Cargo.lock +++ b/pet/tui/Cargo.lock @@ -139,7 +139,7 @@ dependencies = [ [[package]] name = "codewhale-ratatui" -version = "0.1.1" +version = "0.1.2" dependencies = [ "crossterm", "libc", diff --git a/pet/tui/Cargo.toml b/pet/tui/Cargo.toml index 60d8713386..1c688588b2 100644 --- a/pet/tui/Cargo.toml +++ b/pet/tui/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -codewhale-ratatui = { path = "../../vendor/codewhale-ratatui", version = "0.1.1" } +codewhale-ratatui = { path = "../../vendor/codewhale-ratatui", version = "0.1.2" } ratatui = "=0.30.2" unicode-width = "=0.2.2" diff --git a/scripts/release/check-versions.sh b/scripts/release/check-versions.sh index 03caa798bb..a6fa9b4ef5 100755 --- a/scripts/release/check-versions.sh +++ b/scripts/release/check-versions.sh @@ -132,7 +132,7 @@ fi # 4) Internal path dependency pins. internal_dep_drift="$( grep -nE 'codewhale-[a-z-]+[[:space:]]*=[[:space:]]*\{[^}]*version[[:space:]]*=[[:space:]]*"' crates/*/Cargo.toml \ - | grep -vF 'codewhale-ratatui = { path = "../../vendor/codewhale-ratatui", version = "0.1.1" }' \ + | grep -vF 'codewhale-ratatui = { path = "../../vendor/codewhale-ratatui", version = "0.1.2" }' \ | grep -v "version[[:space:]]*=[[:space:]]*\"${workspace_version}\"" || true )" if [[ -n "${internal_dep_drift}" ]]; then diff --git a/scripts/runtime-boundary-baseline.json b/scripts/runtime-boundary-baseline.json index 9abce5e6e2..30d8c6176e 100644 --- a/scripts/runtime-boundary-baseline.json +++ b/scripts/runtime-boundary-baseline.json @@ -2,7 +2,7 @@ "_comment": "Runtime -> UI boundary ratchet (docs/design/TUI_DECONSTRUCTION.md, runtime split). Counts may only go down. Regenerate with python3 scripts/split/module_graph.py --update after removing references; never raise a count by hand.", "totals": { "prod": 11, - "test": 35, + "test": 32, "late": 1, "uilib": 1, "doc": 0 @@ -16,7 +16,6 @@ "client|tui": 3, "config|tui": 2, "core|tui": 2, - "fleet|lib.rs": 3, "prompts|tui": 1, "runtime_api|commands": 2, "session_manager|tui": 3, diff --git a/scripts/runtime-contract-budget.json b/scripts/runtime-contract-budget.json index 48799b8684..99914e11b8 100644 --- a/scripts/runtime-contract-budget.json +++ b/scripts/runtime-contract-budget.json @@ -3,6 +3,7 @@ "_codex_20261005_main_remeasure": "2026-10-05: pair already-merged tool description disclosures with exact hosted Linux measurement on main 3684e2a776fd6ef4f07e8d75e8429d4bed52858b, CI 37359068458 Lint job 111929025135. Only Act/Operate full catalog ceilings failed: 84865 bytes / 21217 estimated tokens versus 84151 / 21038 (+714 B / +179). Accept only that measured increase; tool identities, active/Plan surfaces, prompt and other ceilings unchanged. Estimate only, not provider usage. Wave composition has its own measurement.", "_codex_20261005_wave_remeasure": "2026-10-05: exact provider-free measurement of wave 7903b9645: Act/Operate full 85359 B / 21340 estimated tokens, +644 B / +161 over stale 84715 / 21179. The merged tool-documentation disclosures add 714 B (hosted main measurement); factual description rewrites reduce the common full surface by 70 B (Plan 54336 -> 54266), yielding +644. Only these four numeric ceilings increase. All identity checks and other existing ceilings pass. Receipt CW/artifacts/codex-engine-takeover-20261005/wave-runtime-contract.json. Correction: a53b58b058 incorrectly said this budget check passed; it failed on exactly these four fields. No hosted/native qualification or provider usage implied.", "_codex_20261006_contributor_remeasure": "2026-10-06: provider-free composed release measurement. Existing bounded agent-wait timeout disclosure adds 172 schema bytes to active surfaces; contributor locale descriptions add 189 Plan full / 259 Act and Operate full bytes beyond that shared disclosure. Accept exactly measured tool schema ceilings: Plan full 54697 B / 13675 estimated tokens, active 34882 / 8721; Act and Operate full 85790 / 21448, active 36412 / 9103. All tool identities/counts, prompt identities and skill-discovery contracts remain unchanged. Other measured decreases are locked. Receipt CW/artifacts/takeover-0101-20261005/runtime-contract-final-receipt.json. bytes/4 estimates are not provider usage or billing.", + "_codex_20261011_goal_yield_remeasure": "2026-10-11: update_goal's progress description names yield, which update_goal now accepts with a progress estimate (407cb8ebb3). Hosted Linux measurement, CI run 38144890574 Lint job 114486327862: +7 B on every Plan/Act/Operate full and active surface (+1 to +2 estimated tokens). No tool enters or leaves a surface; identities unchanged.", "_comment": "One-way numeric ceilings and exact structural identities for the provider-free runtime contract. Decreases pass; increases or identity changes fail. Lock in decreases with: python3 scripts/check-runtime-contract-budget.py --update The v0.9.8 child-receipt restore grew every production tool surface by 1496 schema bytes / 374 estimated tokens (agent tool). The v0.9.8 workshop read/tool-result byte fields then grew every production tool surface by 371 schema bytes / 93 estimated tokens. Both raises are explicit maintainer decisions; identities stay on the pre-raise digests only if the name set is unchanged \u2014 re-measure on Linux CI if Lint reports identity drift. The v0.9.8 pinned session prefix added the sentence to the base prompt (5848 -> 6084 bytes, every representative stage re-hashed), and the host-side Workflow/Goal verbs plus honest child posture grew the tool catalog (active 16531 -> 16602 bytes, full 71473 -> 72371); both are explicit v0.9.8 maintainer decisions measured from the release train. The v0.9.9 configured-skills change hides only custom configured-root paths, preserves discoverable default-root paths, normalizes Windows prompt separators, and trims 50 redundant skills-prompt bytes. The skill/memory/goal/handoff identities were re-measured without raising any ceiling. Explicit maintainer decision for #5473/#5492. The v0.9.10 full surfaces intentionally add the safe read_media tool; their measured schemas remain below the prior byte/token ceilings. Representative prompt byte metrics now use the same host-independent normalized text as their identities; the normalized base is 6089 bytes. The v0.9.11 model-visible sub-agent surface intentionally retires six legacy agents/* tools in favor of the canonical agent tool; all affected schema and prompt metrics decrease. The v0.9.12 plugin prompt-match slice intentionally adds the request_plugin_install tool to the full tool surfaces (plan full: +518 schema bytes / +130 estimated tokens / 29 -> 30 tools) so a strong prompt match can surface the human review CTA; explicit maintainer decision for #5663/#5579. The v0.9.13 profile pins a non-executed bare bash shell so interpreter guidance is reproducible across hosts. The duplicate tts catalog entry is intentionally hidden; speech remains canonical and the alias remains available for saved-transcript dispatch. Explicit v0.9.13 maintainer decision (2026-09-08): after removing 1426 repeated guidance bytes and pinning the bash-v2 fixture, accept only the measured tool byte/token ceilings from all-features macOS source e27735bb63c897f88061c71567701fd971f5d396, verified libtest SHA-256 5e8cbe213f32c4ecdec63494c4de5e31857b4a40134edf7b21a55bca926b1b38: active 13274/3319 in every mode, Plan full 39885/9972, Act/Operate full 67603/16901, with no margin. Against the prior budget, active +390 bytes is agent -41 plus retained bash command syntax +431. Plan full also retains Git commit_plan +253, update_goal progress +583, github bounded local-report guidance +127, review complete-input refusal +35, and send_later dispatching status +14. Act/Operate full instead has github +2151 and additionally speech +230, hidden tts -2120, and tasks/automation exact model-route fields +274 each. The older budget predates v0.9.12: that tag had already removed 361 agent bytes and added the two 274-byte route fields; the retained initial increase versus the tag is 751 source-attributed bytes (agent +320, bash +431), not the +390 budget delta. Only the seven active definitions form the initial request; full catalogs include deferred tools. Estimated tokens use the existing bytes/4 heuristic, not provider usage or billing. Prompt, representative-context, skill-discovery and tool-name identities/ceilings are unchanged. Explicit v0.9.13 maintainer decision (2026-09-09): source ccc5dadfa2279545bf084d37cff3617e41ceaae2 intentionally exposes create_goal, get_goal and update_goal before continuation, so all three initial surfaces now contain ten tools. Measure exact source 4648d148eea64782be857eda6952af2c539cbfcc with the hosted macOS all-features libtest SHA-256 4485c88c7a8b66b8bb9a135807321e417a1e266457ecb74cffc7dfb92f850fc4: four exact provider-free metric tests pass. Active schemas are exactly 17847 bytes / 4462 estimated tokens (+4573 / +1143 for the three eager goal definitions); Plan full is 40597 / 10150 and Act/Operate full is 68315 / 17079, with no margin. The +712 full-catalog bytes are request_user_input guidance +358, update_goal state-change guidance +98, list_dir home-relative path guidance +56, explicit review max_passes schema +197, and three defer_loading true-to-false values +3. The three active name sets/digests, their counts, and measured active/full byte/token ceilings change; full name identities and all prompt, representative-context and skill-discovery measurements remain unchanged. This updates the earlier seven-tool initial-request receipt; bytes/4 remains an estimate, not measured provider usage or billing. 2026-10-05: the shell handoff grew every surface by 564 schema bytes / 141 estimated tokens. The bash and action=run descriptions now say a command still running after the foreground wait moves to the background and is not killed, and name task_shell_wait. No tool entered or left a surface. Measured on macOS aarch64; the Linux Lint run reported the same deltas. The one-way numeric and exact identity gates remain enforced. Explicit v0.9.13 maintainer decision (2026-09-10): the +765 active/full tool-schema bytes since source 4648d148ee are exactly source-attributed \u2014 the agent tool's followup/parked-child continuation guidance (b6fad79373: +144 action description, +43 message parameter, +169 resume_from parameter) and the read tool's real output budget (e7f7c71e2c: +164 description, +245 for the new max_bytes parameter). No tool enters or leaves any surface: every name-set identity, count, and all prompt, representative-context and skill-discovery measurements are unchanged; only the measured byte/token ceilings move, to active 18612/4653 in every mode, Plan full 41362/10341, and Act/Operate full 69080/17270, with no margin. bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit v0.9.13 maintainer decision (2026-09-13): source 5bfe88c8e8f45266ea1f9abce87c76b2eed894af intentionally keeps the native workflow tool eager on Plan/Act/Operate first-turn surfaces (DEFAULT_ACTIVE_NATIVE_TOOLS; commit 9e49d0918). Active name sets gain `workflow` (10\u219211 tools); active schema ceilings move to 29402/7351 with margin pending exact Linux --update lock-in. Full catalogs already advertised workflow; only a small defer_loading true\u2192false spelling bump is reserved (+32 bytes / +8 tokens). Prompt, representative-context, and skill-discovery measurements are unchanged. Do not remove workflow from Plan. bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit v0.9.13 maintainer decision (2026-09-13, CI lock-in after b4d48e9a4): Linux Lint run 34766373771 measured the intentional eager `workflow` surface at active 31438/7860 in every mode, Plan full 50801/12701, and Act/Operate full 78513/19629. Prior ceilings (29402/7351 active, Plan full 41394/10349, Act/Operate full 69112/17278) under-counted the workflow schema body plus defer_loading true\u2192false on full catalogs; name-set identities are unchanged and `workflow` stays on Plan. Lock ceilings to those measured values with no margin. bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit v0.9.14 maintainer decision (2026-09-16): #5715 intentionally adds the two bounded read-only recall tools `session_get` and `session_search` to the Act/Operate full catalogs (50 -> 52 tools), so both full name-set identities and their digests move to 1203d192385fd2b02227ef9e4212e5379bc5cbb813a373f12539406b5958aef1. Plan full is unchanged: the session tools are not offered there. Measured on macOS aarch64 all-features from source 55a9e1b778fa; per the 2026-09-13 precedent the exact byte/token ceilings must be re-locked from a Linux Lint run if CI reports drift. bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit v0.9.14 maintainer decision (2026-09-17, #6319): re-measure from source b0866943b4 on macOS aarch64 all-features; per the 2026-09-13 precedent the exact byte/token ceilings must be re-locked from a Linux Lint run if CI reports drift. No tool enters or leaves any surface (52 tools; every name-set identity unchanged). Representative stages and system prompt grow exactly +742 bytes per stage/mode (base 6089 -> 6831, prompt 6084 -> 6826) for the deliberate dc32272f15 Bearing article plus mandate-first scope law; every stage re-hashed. Tool growth is exactly source-attributed per tool (measured per-tool at 55a9e1b778fa vs HEAD): agent +670 (2ca54ea8da #6282 output-token-cap parameter, 3c9c62571a spawn-requirement docs, 85d8dc7501 #6278 exact_files sentence, less 3dcb41f5d2 #6272 release-clause trim and the a7a8bdb338 token-allowance description removal), workflow +424 (a035914336 #6232 plan-child cwd property, serialized twice via phases/items and top-level children/items), Git +867 (b89349286f #6298 merge_tree verify surface), Run +158 (233da9fb76 #6296 bounded cwd), read +91 (f6fb5f42d1 #6283 size/truncated/line_count response fields), create_goal +76 (4de9e9e281 model-decides-goals description rewrite). Active 31453 -> 32714 (+1261 = agent +670, workflow +424, read +91, create_goal +76); Plan full 50816 -> 52944 (+2128 = active +1261 plus Git +867); Act/Operate full 79531 -> 81817 (+2286 = Plan full +2128 plus Run +158). bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit v0.9.14 maintainer decision (2026-09-19 overnight): Code Mode Phase-1 advertises `execute_tools` on Act/Operate full catalogs (52 -> 53 tools; Plan full unchanged). Default Direct mode keeps it deferred (`defer_loading: true`), so active surfaces are unchanged. Name-set identity digests move with the sorted name list; measured tool JSON is 884 bytes (+885 including the catalog comma) so Act/Operate full ceilings lock to 82702/20676. bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit v0.10.0 source reconciliation (2026-09-19): retain the existing agent cwd parameter (+256 serialized bytes in every surface) and tasks create name parameter (+121 bytes in Act/Operate full only), both already present before the preceding execute_tools lock-in. Linux CI run 35490467762 measured active 32970/8243, Plan full 53200/13300, and Act/Operate full 83079/20770. Each increase is attributed to exactly one schema property; no margin, tool identity, prompt or representative-context change. These are schema byte/4 estimates, not billed tokens. Explicit v0.10.0 maintainer decision (2026-09-22): 91b5898a2 intentionally makes `load_skill` eager so the `## Skills` instruction in the base prompt is actually callable \u2014 it was deferred behind tool_search, so the prompt told the model to call a tool that was not in the array it was printed beside. load_skill is read-only, so it joins the active sets of Plan, Act and Operate (11 -> 12 tools; +816 schema bytes / +204 estimated tokens in every mode, active ceilings lock to 33786/8447). Full catalogs move only by the defer_loading true->false spelling plus that schema body (+245 bytes / +61-62 tokens). Representative stages re-hash and each move +149 bytes with the total +37 tokens: dc32272f15 landed the Bearing article and mandate-first scope law, and 91b5898a2 rewrote the Skills paragraph every stage renders. No other name-set identity, count, prompt or skill-discovery measurement changes. Measured from 6bafe6e72 on macOS aarch64 all-features; per the 2026-09-13 precedent the exact byte/token ceilings must be re-locked from a Linux Lint run if CI reports drift. bytes/4 remains an estimate, not measured provider usage or billing. The one-way numeric and exact identity gates remain enforced. Explicit maintainer decision (#6562, PR #6583, 2026-09-25): code mode for MCP is on by default ([features] code_mode = true), so `execute_tools` is eager on the Act/Operate first-turn surfaces (12 -> 13 tools; active 33876/8469 -> 35406/8852, +1530 bytes / +383 estimated tokens) and its definition text now documents nested MCP/plugin calls through the direct-call gate (Act/Operate full 83384/20846 -> 84029/21008, +645 bytes). Plan is unchanged: execute_tools is not offered there. `code_mode = false` restores the prior deferred surface. Measured on macOS aarch64 all-features; re-lock from a Linux Lint run if CI reports drift. Re-measured after merging main 2026-09-25: active 35392/8848 (-14, main's 4b0f54edb fork_context trim), Act/Operate full 83737/20935 (-292: the same -14 plus -278 not attributed per tool in this merge); decreases locked with --update, identities unchanged. bytes/4 remains an estimate, not measured provider usage or billing. Explicit maintainer decision (PR #6589, 2026-09-25): the agent tool declares `runtime` (local|cloud; cloud only proposes a /dispatch job the person confirms) and `remote` (github|cnb|gitee) as schema properties so the model can request a cloud proposal without an undeclared field. Both descriptions were trimmed (-303 bytes) before locking, which also keeps the parent prompt+catalog surface under PARENT_SURFACE_BYTE_CEILING; the remaining +284 bytes / +71 estimated tokens land on every surface that carries agent (Plan/Act/Operate active and full: active 35676/8919 Act/Operate, 34146/8537 Plan; full 84021/21006 Act/Operate, 53785/13447 Plan). No tool enters or leaves any surface; identities unchanged. Measured on macOS aarch64 all-features; re-lock from a Linux Lint run if CI reports drift. bytes/4 remains an estimate, not measured provider usage or billing.", "document_kind": "codewhale.runtime_contract_budget", "representative_context": { @@ -90,9 +91,9 @@ "modes": { "act": { "active": { - "bytes": 37703, + "bytes": 37710, "identity_sha256": "e2d6dfb7168d48ee8d2a415feac7ff5b8864e18528c233a697055370144eb138", - "tokens_est": 9426, + "tokens_est": 9428, "tool_names": [ "agent", "bash", @@ -112,9 +113,9 @@ "tools": 14 }, "full": { - "bytes": 84384, + "bytes": 84391, "identity_sha256": "2a2ee97e7c482c625bc50c77db7f0e08d6bc67e2b4e73e7351385418700252bb", - "tokens_est": 21096, + "tokens_est": 21098, "tool_names": [ "Git", "Run", @@ -173,9 +174,9 @@ }, "operate": { "active": { - "bytes": 37703, + "bytes": 37710, "identity_sha256": "e2d6dfb7168d48ee8d2a415feac7ff5b8864e18528c233a697055370144eb138", - "tokens_est": 9426, + "tokens_est": 9428, "tool_names": [ "agent", "bash", @@ -195,9 +196,9 @@ "tools": 14 }, "full": { - "bytes": 84384, + "bytes": 84391, "identity_sha256": "2a2ee97e7c482c625bc50c77db7f0e08d6bc67e2b4e73e7351385418700252bb", - "tokens_est": 21096, + "tokens_est": 21098, "tool_names": [ "Git", "Run", @@ -256,9 +257,9 @@ }, "plan": { "active": { - "bytes": 36173, + "bytes": 36180, "identity_sha256": "6c432c75bf776d95b367b17308b171c3eaba8e70aa0c2f76bac453b3c3368a21", - "tokens_est": 9044, + "tokens_est": 9045, "tool_names": [ "agent", "bash", @@ -277,9 +278,9 @@ "tools": 13 }, "full": { - "bytes": 55163, + "bytes": 55170, "identity_sha256": "ac8af1f4988199825be7b00b054c258724a44074b1d4e6de6c92ade7c1cffe63", - "tokens_est": 13791, + "tokens_est": 13793, "tool_names": [ "Git", "Web", diff --git a/vendor/codewhale-ratatui/CHANGELOG.md b/vendor/codewhale-ratatui/CHANGELOG.md index 83638324c6..78e4ff5ead 100644 --- a/vendor/codewhale-ratatui/CHANGELOG.md +++ b/vendor/codewhale-ratatui/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.1.2 - 2026-10-11 + +- Let the host paint its prepared pet in `PetMode` (`DotWhale`, + `PetMode::dot_whale`), the API Codewhale 0.10.2 renders the pet through. +- Draw half-block sprites crisply: `Sprite` samples the pixel under each + cell's centre instead of box-filtering, and the whale cove rasterizes one + sample per pixel so shape edges no longer blend into the terminal + background. + ## 0.1.1 - 2026-10-11 - Simplify the native showcase: concise conversation, sparse ambient life, diff --git a/vendor/codewhale-ratatui/Cargo.lock b/vendor/codewhale-ratatui/Cargo.lock index 9509ad9149..878afa3eff 100644 --- a/vendor/codewhale-ratatui/Cargo.lock +++ b/vendor/codewhale-ratatui/Cargo.lock @@ -61,7 +61,7 @@ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "codewhale-ratatui" -version = "0.1.1" +version = "0.1.2" dependencies = [ "crossterm", "insta", diff --git a/vendor/codewhale-ratatui/Cargo.toml b/vendor/codewhale-ratatui/Cargo.toml index 3acf6e36a1..6cd63b7700 100644 --- a/vendor/codewhale-ratatui/Cargo.toml +++ b/vendor/codewhale-ratatui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codewhale-ratatui" -version = "0.1.1" +version = "0.1.2" edition = "2024" rust-version = "1.89" license = "MIT" diff --git a/vendor/codewhale-ratatui/UPSTREAM.json b/vendor/codewhale-ratatui/UPSTREAM.json index 6c7dcb3bea..8003a22fa3 100644 --- a/vendor/codewhale-ratatui/UPSTREAM.json +++ b/vendor/codewhale-ratatui/UPSTREAM.json @@ -187,16 +187,16 @@ "vendor/codewhale-design/tokens.rs": "975b7a4e2cda30f9dfa642283f092b9770529c5ec8c401d05b9bde5b6e55bdd1" }, "pet_update": { - "commit": "00c6505356c5264fa6fd7d01f66458624d03e951", + "commit": "8f51c6bccadeb11278cda1e2481a116573e5d233", "scope": "Selected prepared pet renderer files; non-pet components retain the base snapshot and existing Engine patches.", "files": { - "src/avatar_sprite.rs": "efa14ec46bae22772f01fa28375c4f75cb8fe3696ca29f392b157b6173e1adee", + "src/avatar_sprite.rs": "2d76da6667d24fbcd36a22d5a70c8ef9136eb1b853bb32884cf236ee0cce92b6", "src/color.rs": "96c44be1540c4756f251ed5ffb74aa88a5ebf131b104bf25866ad7ab8e3c6ba8", "src/components/dot_whale.rs": "191bacf808037ba4dd7d4dfffbd06fe9c951a258a31495380591ad6ab4a715fa", "src/components/pet_mode.rs": "35142d709073a09720f1ce1cfb57b18d6ea4880530a5c8d96755c5b9fc203214", "src/components/whale_pet.rs": "bb29442f8db20e8387482e2e1dcb4fa5259ef99c3a37a77bfe9e4b56eaa05aed", "src/whale.rs": "126a6efc8cac550ccd7f9c8edc61745b8c959186de118c2f4d479f5a5c5ffcf7", - "src/whale_motion/pixels.rs": "f232f48a1a9c36339b3dd78e9c5ae5a2043d08749d023977bc39633821ad0bb6" + "src/whale_motion/pixels.rs": "f83113863c7928cc93dbbc7b187d6f9346d1848ffb9636fd3d8551faa9de69d9" }, "merged_exports": { "src/components/mod.rs": "0ea81b474b2137b177c5535e7523ed6b312ea972630ac94f5131883246496e8e" diff --git a/vendor/codewhale-ratatui/src/avatar_sprite.rs b/vendor/codewhale-ratatui/src/avatar_sprite.rs index 5aaf0668f8..c92ceb5794 100644 --- a/vendor/codewhale-ratatui/src/avatar_sprite.rs +++ b/vendor/codewhale-ratatui/src/avatar_sprite.rs @@ -94,42 +94,10 @@ impl<'a> Sprite<'a> { } fn sample(&self, x: usize, y: usize, width: usize, height: usize) -> [u8; 4] { - if width == self.width && height == self.height { - return self.pixel(x, y); - } - let bounds = |position: usize, source: usize, target: usize| { - let scale = source as f64 / target as f64; - let center = (position as f64 + 0.5) * scale; - let radius = scale.max(1.) / 2.; - ( - (center - radius).max(0.), - (center + radius).min(source as f64), - ) - }; - let (left, right) = bounds(x, self.width, width); - let (top, bottom) = bounds(y, self.height, height); - let mut rgba = [0.; 4]; - for sy in top.floor() as usize..(bottom.ceil() as usize).min(self.height) { - let weight_y = (bottom.min(sy as f64 + 1.) - top.max(sy as f64)).max(0.); - for sx in left.floor() as usize..(right.ceil() as usize).min(self.width) { - let weight_x = (right.min(sx as f64 + 1.) - left.max(sx as f64)).max(0.); - let pixel = self.pixel(sx, sy); - let alpha = f64::from(pixel[3]) * weight_x * weight_y; - for channel in 0..3 { - rgba[channel] += f64::from(pixel[channel]) * alpha; - } - rgba[3] += alpha; - } - } - if rgba[3] == 0. { - return [0; 4]; - } - [ - (rgba[0] / rgba[3]).round() as u8, - (rgba[1] / rgba[3]).round() as u8, - (rgba[2] / rgba[3]).round() as u8, - (rgba[3] / ((right - left) * (bottom - top))).round() as u8, - ] + self.pixel( + ((2 * x + 1) * self.width / (2 * width)).min(self.width - 1), + ((2 * y + 1) * self.height / (2 * height)).min(self.height - 1), + ) } } impl Paint for Sprite<'_> { diff --git a/vendor/codewhale-ratatui/src/whale_motion/pixels.rs b/vendor/codewhale-ratatui/src/whale_motion/pixels.rs index 674e0916d6..8569fe448f 100644 --- a/vendor/codewhale-ratatui/src/whale_motion/pixels.rs +++ b/vendor/codewhale-ratatui/src/whale_motion/pixels.rs @@ -80,13 +80,14 @@ impl Canvas { } } -/// Square design space, with extra samples at small sizes for clean curved edges. +/// Square design space at one sample per pixel, so shape edges stay hard on a +/// half-block grid instead of blending into the terminal background. /// Public terminal rectangles never control an unbounded allocation. pub(crate) fn render(scene: &CoveScene, side: usize, dark: bool) -> Vec { if !(1..=MAX_SIDE).contains(&side) { return Vec::new(); } - let samples = if side <= 64 { 4 } else { 2 }; + let samples = 1; let mut canvas = Canvas { side: side * samples, pixels: vec![[0.; 4]; side * side * samples * samples], diff --git a/web/lib/release-credits.ts b/web/lib/release-credits.ts index 416e214f4c..a4fbfc34ec 100644 --- a/web/lib/release-credits.ts +++ b/web/lib/release-credits.ts @@ -26,6 +26,7 @@ export const RELEASE_CONTRIBUTORS: string[] = [ "@Lstarsky0", "@jayanthvee", "@asto18089", + "@LIghtJUNction", ]; /** @@ -33,7 +34,7 @@ export const RELEASE_CONTRIBUTORS: string[] = [ * one. scripts/check-contributor-credit.py requires them here now; the release * cut moves them into RELEASE_CONTRIBUTORS with that release's changelog block. */ -export const UNRELEASED_CONTRIBUTORS: string[] = ["@LIghtJUNction"]; +export const UNRELEASED_CONTRIBUTORS: string[] = []; /** * Contributors who helped with reports, reproductions, and verification.