zidane 7.0.31 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -2
- package/dist/{acp-m3TLCY_C.js → acp-B5UfEhMd.js} +4 -4
- package/dist/{acp-m3TLCY_C.js.map → acp-B5UfEhMd.js.map} +1 -1
- package/dist/acp-cli.js +6 -6
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-9gf8ZlBR.js → agent-_xxElOgH.js} +307 -33
- package/dist/agent-_xxElOgH.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{anthropic-B4UmPm4H.js → anthropic-DPPs3wjJ.js} +111 -7
- package/dist/anthropic-DPPs3wjJ.js.map +1 -0
- package/dist/{approvals-DaCEPCTV.js → approvals-u2T19Dc-.js} +297 -95
- package/dist/approvals-u2T19Dc-.js.map +1 -0
- package/dist/{auth-CJogE9q7.js → auth-HRKkOErn.js} +3 -3
- package/dist/{auth-CJogE9q7.js.map → auth-HRKkOErn.js.map} +1 -1
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat/pure.js +1 -1
- package/dist/chat.d.ts +6 -6
- package/dist/chat.js +8 -8
- package/dist/contexts/daytona.d.ts +3 -3
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +2 -2
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/{contexts-BSFQVclW.js → contexts-CRE9pw07.js} +544 -17
- package/dist/contexts-CRE9pw07.js.map +1 -0
- package/dist/contexts.d.ts +4 -4
- package/dist/contexts.js +2 -2
- package/dist/daemon-cli.js +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +3 -3
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +3 -3
- package/dist/{index-B6FkK6ZN.d.ts → index-C37_ppWv.d.ts} +2 -2
- package/dist/index-C37_ppWv.d.ts.map +1 -0
- package/dist/{index-JkEO3MBV.d.ts → index-D3TTaaQ5.d.ts} +39 -7
- package/dist/index-D3TTaaQ5.d.ts.map +1 -0
- package/dist/{index-hd4zLhp8.d.ts → index-DZhrTn-v.d.ts} +307 -16
- package/dist/index-DZhrTn-v.d.ts.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +8 -8
- package/dist/{ipc-BtN5SIc0.js → ipc-DwauKEE-.js} +3 -3
- package/dist/{ipc-BtN5SIc0.js.map → ipc-DwauKEE-.js.map} +1 -1
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +3 -3
- package/dist/{types-U-rIVUDw.d.ts → isolation-Kfoof0MM.d.ts} +93 -2
- package/dist/isolation-Kfoof0MM.d.ts.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/{plugins-B531Tz5b.js → plugins-gbI7SBA6.js} +3 -3
- package/dist/{plugins-B531Tz5b.js.map → plugins-gbI7SBA6.js.map} +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +1 -1
- package/dist/restate.d.ts +2 -2
- package/dist/restate.js +1 -1
- package/dist/{sandbox-CDl9tfTo.d.ts → sandbox-BH0WQkXn.d.ts} +2 -2
- package/dist/{sandbox-CDl9tfTo.d.ts.map → sandbox-BH0WQkXn.d.ts.map} +1 -1
- package/dist/{server-ktOMu5gk.js → server-DvPnPSZb.js} +8 -8
- package/dist/{server-ktOMu5gk.js.map → server-DvPnPSZb.js.map} +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +7 -0
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-CVy-2mAy.js → session-BqRP1hS7.js} +33 -3
- package/dist/session-BqRP1hS7.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/{skills-PJyiSRCp.js → skills-BC3dodWp.js} +2 -2
- package/dist/{skills-PJyiSRCp.js.map → skills-BC3dodWp.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +1 -1
- package/dist/{src-CjkY6fBj.js → src-CkNQKFKr.js} +3 -3
- package/dist/{src-CjkY6fBj.js.map → src-CkNQKFKr.js.map} +1 -1
- package/dist/{tool-formatters-C4QIFCNa.d.ts → tool-formatters-C5s88MUd.d.ts} +2 -2
- package/dist/{tool-formatters-C4QIFCNa.d.ts.map → tool-formatters-C5s88MUd.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-Bbn1HX5D.d.ts → transcript-anchors-DxofXw_y.d.ts} +3 -3
- package/dist/transcript-anchors-DxofXw_y.d.ts.map +1 -0
- package/dist/tui.d.ts +21 -28
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +200 -74
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-BgqpLlOG.js → turn-operations-6JDu2ewy.js} +24 -2
- package/dist/{turn-operations-BgqpLlOG.js.map → turn-operations-6JDu2ewy.js.map} +1 -1
- package/dist/{turn-operations-BhHCpCkP.d.ts → turn-operations-BaQnxzhr.d.ts} +14 -4
- package/dist/{turn-operations-BhHCpCkP.d.ts.map → turn-operations-BaQnxzhr.d.ts.map} +1 -1
- package/dist/types-CWgENVLY.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/docs/ARCHITECTURE.md +13 -3
- package/docs/CHAT.md +9 -0
- package/docs/EXECUTION_CONTEXT.md +64 -3
- package/docs/INTERACTIONS.md +14 -2
- package/docs/SKILL.md +31 -1
- package/docs/TUI.md +6 -5
- package/package.json +1 -1
- package/dist/agent-9gf8ZlBR.js.map +0 -1
- package/dist/anthropic-B4UmPm4H.js.map +0 -1
- package/dist/approvals-DaCEPCTV.js.map +0 -1
- package/dist/contexts-BSFQVclW.js.map +0 -1
- package/dist/index-B6FkK6ZN.d.ts.map +0 -1
- package/dist/index-JkEO3MBV.d.ts.map +0 -1
- package/dist/index-hd4zLhp8.d.ts.map +0 -1
- package/dist/session-CVy-2mAy.js.map +0 -1
- package/dist/transcript-anchors-Bbn1HX5D.d.ts.map +0 -1
- package/dist/types-U-rIVUDw.d.ts.map +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $_ as
|
|
1
|
+
import { $_ as SkillsConfig, $g as SessionHookContext, Ah as AnthropicParams, B_ as StagedToolState, Bg as PromptDocumentPart, Br as InteractionToolOptions, C as SuccessfulMutationOutcome, C_ as TurnUsage, Cm as StreamOptions, D_ as ToolContext, Dm as ToolSpec, E_ as toolResultToText, Eg as DEFAULT_AGENT_CLOCK, Em as ToolResult, Gg as RepeatGuardConfig, H_ as ToolStateOp, Hg as PromptPart, Ig as OAuthRefreshHookContext, Jg as ResolveContentRefBlock, Ji as AgentHookMap, Kg as RepeatGuardToolMatcher, Lg as ProgressNudgeKind, M_ as ReadStateMap, Mg as McpToolHookContext, O_ as ToolDef, Om as TurnResult, Qg as SessionEndStatus, Rg as ProgressNudgeMessage, S as MutationValidationResult, S_ as TurnFinishReason, Sm as StreamCallbacks, T_ as toolOutputByteLength, Tm as ToolCall, U_ as ToolStateStore, Ug as PromptTextPart, V_ as ToolStateController, Vg as PromptImagePart, W_ as ToolStateView, Wg as PromptVideoPart, Xg as RunHookMap, Xi as AgentOptions, Y_ as SkillConfig, Yg as RetryConfig, Yi as AgentHooks, Z_ as SkillResource, Zg as SessionContentBlock, Zi as AgentToolState, _ as statsByModel, __ as ToolResultImageContent, _g as AgentStats, a_ as StreamHookContext, av as SessionRun, b as MutationValidationHooksOptions, b_ as ToolResultTextContent, bm as ProviderCapabilities, d_ as ToolHookContext, e_ as SessionMessage, ev as CreateSessionOptions, f_ as ToolOutcome, g_ as ToolResultDocumentRefContent, gc as SpawnToolState, gg as AgentRunOptions, gv as RemoteStoreOptions, h as flattenTurns, h_ as ToolResultDocumentContent, hc as SpawnToolOptions, hg as AgentClock, j_ as ReadStateEntry, jg as McpServerConfig, k_ as ToolMap, l_ as ThinkingLevel, lh as OpenAIParams, m_ as ToolResultContent, mg as AgentBehavior, n_ as SpawnHookContext, nv as Session, ov as SessionStore, p as ModelUsage, p_ as ToolResultAudioContent, qg as ResolveContentRef, qi as Agent, rv as SessionData, sy as McpConnection, t as Preset, t_ as SessionTurn, uc as ChildAgent, v as MutationValidationBatch, v_ as ToolResultImageRefContent, vr as ValidationResult, w_ as toolOutputBudgetByteLength, x as MutationValidationMutation, x_ as ToolResultVideoContent, xg as ChildRunStats, xh as CerebrasParams, y as MutationValidationFailure, y_ as ToolResultMetadata, ym as Provider, zg as PromptAudioPart, zm as OpenRouterParams } from "./index-DZhrTn-v.js";
|
|
2
2
|
import { d as ClassifiedErrorKind, i as AgentContextExceededError, l as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, n as AgentAbortedError, o as AgentProviderError, p as matchesContextExceeded, r as AgentBudgetExceededError, s as AgentToolNotAllowedError, u as ClassifiedError } from "./timeout-DEaqslLO.js";
|
|
3
|
-
import {
|
|
4
|
-
import { t as SandboxProvider } from "./sandbox-
|
|
3
|
+
import { C as TaskHandle, S as TaskExitInfo, c as ContextCapabilities, d as ContextType, f as DetachedTasksCapability, h as ExecutionHandle, l as ContextHardening, m as ExecutionContext, p as ExecResult, s as BackgroundTaskStatus, w as TaskStallInfo, x as TaskEntry, y as SpawnConfig } from "./isolation-Kfoof0MM.js";
|
|
4
|
+
import { t as SandboxProvider } from "./sandbox-BH0WQkXn.js";
|
|
5
5
|
export { type Agent, AgentAbortedError, type AgentBehavior, AgentBudgetExceededError, type AgentClock, AgentContextExceededError, type AgentHookMap, type AgentHooks, type AgentOptions, AgentProviderError, type AgentRunOptions, type AgentStats, AgentToolNotAllowedError, type AgentToolState, type AnthropicParams, type BackgroundTaskStatus, CONTEXT_EXCEEDED_MESSAGE_PATTERNS, type CerebrasParams, type ChildAgent, type ChildRunStats, type ClassifiedError, type ClassifiedErrorKind, type ContextCapabilities, type ContextHardening, type ContextType, type CreateSessionOptions, DEFAULT_AGENT_CLOCK, type DetachedTasksCapability, type ExecResult, type ExecutionContext, type ExecutionHandle, type InteractionToolOptions, type McpConnection, type McpServerConfig, type McpToolHookContext, type ModelUsage, type MutationValidationBatch, type MutationValidationFailure, type MutationValidationHooksOptions, type MutationValidationMutation, type MutationValidationResult, type OAuthRefreshHookContext, type OpenAIParams, type OpenRouterParams, type Preset, type ProgressNudgeKind, type ProgressNudgeMessage, type PromptAudioPart, type PromptDocumentPart, type PromptImagePart, type PromptPart, type PromptTextPart, type PromptVideoPart, type Provider, type ProviderCapabilities, type ReadStateEntry, type ReadStateMap, type RemoteStoreOptions, type RepeatGuardConfig, type RepeatGuardToolMatcher, type ResolveContentRef, type ResolveContentRefBlock, type RetryConfig, type RunHookMap, type SandboxProvider, type Session, type SessionContentBlock, type SessionData, type SessionEndStatus, type SessionHookContext, type SessionMessage, type SessionRun, type SessionStore, type SessionTurn, type SkillConfig, type SkillResource, type SkillsConfig, type SpawnConfig, type SpawnHookContext, type SpawnToolOptions, type SpawnToolState, type StagedToolState, type StreamCallbacks, type StreamHookContext, type StreamOptions, type SuccessfulMutationOutcome, type TaskEntry, type TaskExitInfo, type TaskHandle, type TaskStallInfo, type ThinkingLevel, type ToolCall, type ToolContext, type ToolDef, type ToolHookContext, type ToolMap, type ToolOutcome, type ToolResult, type ToolResultAudioContent, type ToolResultContent, type ToolResultDocumentContent, type ToolResultDocumentRefContent, type ToolResultImageContent, type ToolResultImageRefContent, type ToolResultMetadata, type ToolResultTextContent, type ToolResultVideoContent, type ToolSpec, type ToolStateController, type ToolStateOp, type ToolStateStore, type ToolStateView, type TurnFinishReason, type TurnResult, type TurnUsage, type ValidationResult, flattenTurns, matchesContextExceeded, statsByModel, toolOutputBudgetByteLength, toolOutputByteLength, toolResultToText };
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -312,6 +312,7 @@ A prefix cache breaks at the first differing byte — the wire must be append-on
|
|
|
312
312
|
| `thinkingDecay` | Step form `{ afterTurn, floor }` | Every distinct budget is one cache loss; step emits one change per run, geometric emits one per halving, a per-turn function disables caching for the rest of the run. |
|
|
313
313
|
| `cacheTtl` | `'1h'` for interactive hosts, `'5m'` for headless back-to-back runs | The 5-minute default TTL is the dominant cache cost for a human-paced session. |
|
|
314
314
|
| `compactStrategy` / `mediaKeepTurns` | Keep windows equal, chunk-aligned (`COMPACT_CHUNK_TURNS`) | A window then costs one invalidation, not two. |
|
|
315
|
+
| `compactThresholdWindowFraction` | `0.25` for interactive hosts | Each tail-compaction frontier step rewrites an early message and re-bills the whole suffix (~50x the cost of keeping the bytes cached). Scaling the byte threshold with the model's window removes the steps on large-context models; ≤128k models keep the byte rule. Live A/B in `test-inference/cache-stability.inference.test.ts` § tail compaction vs context window. |
|
|
315
316
|
| `thinking` level | Constant for the whole run | The thinking config is part of the cache key like the budget; toggling it mid-run forfeits the prefix. |
|
|
316
317
|
| `system:transform` handlers | Byte-stable output only | Per-turn counters/timestamps belong in the transcript, not the system prompt. |
|
|
317
318
|
|
|
@@ -439,16 +440,25 @@ installLazyDisclosureGate // tool:gate refuses lazy ∉ u
|
|
|
439
440
|
|
|
440
441
|
per turn — buildFormattedTools() emits in two phases:
|
|
441
442
|
1. registry-order walk filtered by initialUnlocked ← byte-stable cached prefix
|
|
442
|
-
2. dynamicUnlockOrder, in unlock order ← append-only tail
|
|
443
|
+
2. dynamicUnlockOrder, in unlock order ← append-only tail (omitted in dispatch mode)
|
|
443
444
|
|
|
444
445
|
tool_search({ names | query | server, limit? }): unlocks matches, returns inlined input_schema JSON
|
|
445
446
|
|
|
447
|
+
dispatch mode (toolSearch.mode: 'dispatch'):
|
|
448
|
+
tools.call_tool = createCallToolTool() ← eager, fixed { name, arguments } envelope
|
|
449
|
+
model: call_tool({ name: 'mcp_srv_a', arguments })
|
|
450
|
+
loop (after wire→canonical rewrite): unwrapDispatchCalls()
|
|
451
|
+
→ ToolCall { id, name: 'mcp_srv_a', input: arguments } for gate / validation / hooks / events
|
|
452
|
+
persisted assistant turn keeps the call_tool block ← wire-valid history
|
|
453
|
+
store.eventsFromTurns: unwrapCallTool() on replay ← reload matches the live transcript
|
|
454
|
+
|
|
446
455
|
run end: uninstallLazyDisclosureGate; per-run state GC-eligible on next run()
|
|
447
456
|
```
|
|
448
457
|
|
|
449
458
|
- **Aliasing.** `LazyToolEntry.name` is the wire name; `.canonicalName` keys `unlocked` and dispatches `ctx.tools[name]`. `session.turns` / `ToolHookContext.name` stay canonical throughout.
|
|
450
459
|
- **Hard gate vs. provider validation.** Anthropic/OpenAI already refuse `tool_use` blocks for tools absent from the request; the gate exists for lenient/custom/mock providers and makes the lazy boundary observable via `tool:gate`.
|
|
451
|
-
- **Cache
|
|
460
|
+
- **Cache cost of unlock mode.** The eager + `tool_search` prefix of the wire array never moves, but providers hash the request as `tools → system → messages`: a grown tail still re-bills the system prompt and every message on that turn. That is one full prompt-cache rewrite per discovery wave.
|
|
461
|
+
- **Dispatch mode.** `toolSearch.mode: 'dispatch'` keeps the tools array byte-stable: surfaced tools are invoked through `call_tool` (`src/tools/call-tool.ts`). The unwrap happens once, in `runTurn` right after the alias rewrite, so the whole downstream pipeline (lazy gate, MCP gates, `validateToolArgs` against the INNER schema, `tool:before/after`, tracing, run counts, both dispatch paths) is unchanged and sees the inner tool. Only lazy catalog tools are unwrapped: an envelope around an eager tool stays a `call_tool` call and its `execute` says to call the tool directly (history scanners keyed on `block.name`, read-state seeding, task tracking, keep seeing eager tools under their own names). A malformed envelope is left as `call_tool` so its own schema validation reports the shape error. A host-defined `call_tool` disables dispatch mode (the run falls back to unlock). The chat hosts expose this as `Settings.stableToolList`.
|
|
452
462
|
- **Host-defined `tool_search`.** A host tool named `tool_search` shadows auto-injection; it must call `createToolSearchTool({ catalog, unlocked, addUnlock? })` to drive unlocks, or use `toolSearch.tool: false` for a fully custom flow.
|
|
453
463
|
|
|
454
464
|
## Hook Firing Order
|
|
@@ -661,7 +671,7 @@ Use `agent.hooks.hook(event, fn)` for dynamic post-creation registration (return
|
|
|
661
671
|
**Defaults:** unlimited turns, model-driven output tokens, level-based thinking, `cache: true`, `dedupReads: true`, `requireReadBeforeEdit: false`, `maxConcurrentTools: 10`, `compactStrategy: 'off'`, `compactThreshold: 128 KiB`, `compactKeepTurns: 4`, `toolDisclosure: 'eager'`, `readLineNumbers: true`, `elideStaleReads: false`, `surfaceMcpInstructions: true`, `maxConsecutivePauseTurns: 0` (unlimited), `persistTurns: true`, `providerStreamStartTimeoutMs: 300000`, `providerStreamTimeoutMs: 1800000`, `mcpConnectTimeoutMs: 120000`. All other knobs below default to `undefined`/off unless noted. The chat-layer profiles (`BUILD_AGENT`/`PLAN_AGENT`) override several — see `docs/CHAT.md` § Agents.
|
|
662
672
|
|
|
663
673
|
- **`toolOutputBudget`** (off). Sums every result's `outputBytes` after `tool:transform`. On overshoot, appends a synthetic user message (`[Tool output budget exceeded: N bytes … cap: M]`) and fires `budget:exceeded` — the model self-compacts next turn instead of being cut.
|
|
664
|
-
- **`compactStrategy: 'tail' | CompactFunction'`** — client-side, wire-only trim for non-Anthropic providers. `'tail'` stubs `tool_result` blocks older than `compactKeepTurns` past a byte threshold; `session.turns` is untouched. Anthropic should prefer server-side `context-management-2025-06-27` (token-accurate). A custom function must preserve `tool_use ↔ tool_result` adjacency and the trailing user message.
|
|
674
|
+
- **`compactStrategy: 'tail' | CompactFunction'`** — client-side, wire-only trim for non-Anthropic providers. `'tail'` stubs `tool_result` blocks older than `compactKeepTurns` past a byte threshold (`compactThreshold`, raised to `compactThresholdWindowFraction × contextWindow × 4 B` when the run knows its window — `autoCompact.contextWindow`, the active `ModelTarget`, or `provider.meta.contextWindow`); `session.turns` is untouched. Anthropic should prefer server-side `context-management-2025-06-27` (token-accurate). A custom function must preserve `tool_use ↔ tool_result` adjacency and the trailing user message.
|
|
665
675
|
- **`mediaKeepTurns`** — wire-only media age-out. Inline `image`/`document` blocks older than N messages become an `attachment://<hash>` marker on the wire; `session.turns` keeps the bytes, `read_file path="attachment://<hash>"` re-inlines. Chunk-snapped for cache stability; requires `read_file` registered to be actionable.
|
|
666
676
|
- **`autoCompact`** (`boolean | AutoCompactConfig`, off). At each turn boundary, once effective input (`input + cacheRead + cacheCreation`) crosses `threshold` (default `0.85`) of the context window, summarizes older turns and continues. Window source: `autoCompact.contextWindow` → `provider.meta.contextWindow`, else inert. `minGrowthFraction` (default `0.1`) stops post-compact thrashing; `maxFailures` (default `2`) disables it after consecutive summary failures. Chat profiles enable at `{ threshold: 0.85 }`.
|
|
667
677
|
- **`modelCatalog`** — override model metadata keyed `"<provider>:<modelId>"` or via `{ get, list }`. Resolution: run → agent `behavior.modelCatalog` → process-wide `setModelCatalog()` → bundled registry → local fallback tables, merged field-level. `list` returning `[]` empties a provider's picker; `get` returning `undefined` falls through. Unset by default.
|
package/docs/CHAT.md
CHANGED
|
@@ -166,6 +166,10 @@ const SHARED_BEHAVIOR: AgentBehavior = {
|
|
|
166
166
|
// context / token discipline
|
|
167
167
|
compactStrategy: 'tail',
|
|
168
168
|
compactThreshold: 128 * 1024,
|
|
169
|
+
compactThresholdWindowFraction: 0.25, // effective threshold = max(128 KiB,
|
|
170
|
+
// 0.25 × window × 4 B/tok): 1M-context
|
|
171
|
+
// runs never trip tail compaction on
|
|
172
|
+
// ordinary sessions; ≤128k stays on bytes
|
|
169
173
|
compactKeepTurns: 8, // floor, not a cap — see below
|
|
170
174
|
elideStaleReads: 'notice', // append-only staleness note; never rewrites
|
|
171
175
|
// cached prefix bytes ('stub' re-bills the
|
|
@@ -247,9 +251,14 @@ Both join `[...doctrine, userInstructions]` as the **static** half and `[envSect
|
|
|
247
251
|
| `showAllProjects` | `boolean` | `false` | Sessions list scope. |
|
|
248
252
|
| `resumeLastSession` | `boolean` | `true` | |
|
|
249
253
|
| `persistToolResults` | `boolean` | `true` | See **Tool-result persistence**. |
|
|
254
|
+
| `stableToolList` | `boolean` | `false` | Lazy MCP tools surfaced by `tool_search` are invoked through `call_tool` instead of growing the model's tool list (`behavior.toolSearch.mode: 'dispatch'`), so discovery never rewrites the prompt cache. Transcript shows the inner tool as with a direct call. Anthropic always uses dispatch (replayed thinking is bound to the tool list — see Preserved thinking in `SKILL.md`); the toggle only affects other providers. |
|
|
255
|
+
| `sandbox` | `boolean` | `false` | Run the model's `shell` commands under the OS sandbox (macOS Seatbelt / Linux bwrap). Writes limited to cwd, temp dirs, a worktree's git dir and `sandboxAllowWrite`; credential dirs unreadable; `write_file`/`edit` follow the same roots. Not covered: `!` commands, MCP servers, `fetch_url`, reads. Fails closed when the backend is missing (a `sandbox` notice explains on activation). Resolved by `chat/sandbox-settings.ts` → `SpawnConfig.isolation`; see `docs/EXECUTION_CONTEXT.md`. Next session activation. |
|
|
256
|
+
| `sandboxNetwork` | `'allow'\|'deny'` | `'allow'` | Network for sandboxed commands. `deny` removes all sockets — the only way to stop exfiltration of readable files, at the cost of `bun install` / `git fetch`. |
|
|
257
|
+
| `sandboxAllowWrite` | `string` | `''` | Extra writable paths, comma/newline separated, `~` expanded, relative to cwd. |
|
|
250
258
|
| `autoCompact` | `boolean` | `true` | See **Auto-compaction**. |
|
|
251
259
|
| `autoCompactThreshold` | `number` | `0.8` | Cycles 0.6/0.7/0.8/0.9 in the settings modal. |
|
|
252
260
|
| `resumeOnMaxTokens`, `maxOutputTokens`, `maxTurns`, `retryMaxAttempts`, `maxCostUsd`, `maxTotalTokens`, `maxWallMinutes` | mixed | off/`0` | Runaway ceilings; all off by default (model-driven, uncapped). |
|
|
261
|
+
| `thinkingBinding` | `'drop_block' \| 'error' \| 'off'` | `'drop_block'` | Anthropic only. What the API does with replayed thinking whose prefix changed: drop server-side and continue, fail the run with the API's 400 (no retry, history untouched — debugging), or account default. Published to `ZIDANE_THINKING_BINDING_SETTING` by the TUI on change and by the chat host per send; the provider reads it per request. Precedence: `anthropic({ thinkingBinding })` > `ZIDANE_THINKING_BINDING` set in the launching shell > this setting > `'drop_block'`. |
|
|
253
262
|
| `showEditDiffs` | `boolean` | `true` | See **Edit-diff rendering**. |
|
|
254
263
|
| `editDiffDisplay` | `'full'\|'compact'` | `'full'` | Approval modal always shows the full diff regardless. |
|
|
255
264
|
| `showCompactionSummary` | `boolean` | `false` | Render the LLM summary text under the compaction card, not just metadata. |
|
|
@@ -275,9 +275,70 @@ bun run headless "fix the lint errors" --cwd /tmp/project
|
|
|
275
275
|
Applicable flags: `--cwd` (defaults to the current directory), `--env`, and
|
|
276
276
|
`--pass-env`. The `--image`, `--pregame`, and `--sandbox` flags don't apply.
|
|
277
277
|
|
|
278
|
-
Because there's no isolation, the agent's commands can read and
|
|
279
|
-
your own shell can. Prefer `docker` or `e2b` when you don't
|
|
280
|
-
agent might run
|
|
278
|
+
Because there's no isolation by default, the agent's commands can read and
|
|
279
|
+
modify anything your own shell can. Prefer `docker` or `e2b` when you don't
|
|
280
|
+
fully trust what the agent might run, or turn on the OS sandbox below for a
|
|
281
|
+
lightweight middle ground.
|
|
282
|
+
|
|
283
|
+
### OS sandbox (`isolation`)
|
|
284
|
+
|
|
285
|
+
`createProcessContext({ cwd, isolation })` wraps every shell command in a
|
|
286
|
+
kernel-enforced sandbox — the same primitive Claude Code and Codex use:
|
|
287
|
+
|
|
288
|
+
| Platform | Backend | Mechanism |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| macOS | `/usr/bin/sandbox-exec` (Seatbelt) | deny-default SBPL profile derived from Codex's base policy; paths are passed as `-D` params, never inlined |
|
|
291
|
+
| Linux | `bwrap` (bubblewrap) | `--ro-bind / /`, per-root `--bind`, `--tmpfs` over credential dirs, `--unshare-net` when denied |
|
|
292
|
+
| Windows | — | unsupported; requesting isolation fails closed |
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
import { createProcessContext, resolveWritableRoots } from 'zidane'
|
|
296
|
+
|
|
297
|
+
const execution = createProcessContext({
|
|
298
|
+
cwd,
|
|
299
|
+
isolation: {
|
|
300
|
+
writableRoots: resolveWritableRoots(cwd, { extra: ['~/.cache'] }),
|
|
301
|
+
network: 'allow', // or 'deny'
|
|
302
|
+
},
|
|
303
|
+
})
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Policy.** `writableRoots` is where commands may create / modify / delete;
|
|
307
|
+
`resolveWritableRoots` (sync) / `resolveWritableRootsAsync` build the default set: `cwd`, `$TMPDIR`, `/tmp`,
|
|
308
|
+
`/var/tmp` (+ `/private` aliases on macOS), git's common dir when `cwd` is a
|
|
309
|
+
linked worktree (otherwise `git commit` fails there), plus extras — all
|
|
310
|
+
canonicalized and deduped. Reads are allowed everywhere except
|
|
311
|
+
`unreadableDirs` (default: `~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.kube`,
|
|
312
|
+
`~/.azure`, `~/.config/gcloud`, `~/.docker/config.json`, `~/.netrc`,
|
|
313
|
+
zidane's `credentials.json` and `mcp-credentials.json`; the chat hosts
|
|
314
|
+
resolve the latter two from the actual data dir). `network` is
|
|
315
|
+
all-or-nothing; per-domain allowlists need a proxy and are not implemented.
|
|
316
|
+
|
|
317
|
+
**Scope.** Kernel enforcement covers `exec`, `execStream` and
|
|
318
|
+
`execBackground` — i.e. the model's `shell` tool and anything else routed
|
|
319
|
+
through the context (stdio MCP servers bound to it, subagents). `writeFile`
|
|
320
|
+
applies the same `writableRoots` in-process, so `write_file` / `edit` /
|
|
321
|
+
`multi_edit` cannot write where a shell command couldn't. `readFile`, `glob`
|
|
322
|
+
and `listFiles` are unrestricted (persisted tool outputs and skills under
|
|
323
|
+
`~/.zidane` / `~/.agents` must stay reachable). Not covered: MCP servers
|
|
324
|
+
spawned by the host, `fetch_url`, the `!` shell in the TUI, `$EDITOR`.
|
|
325
|
+
|
|
326
|
+
**Fail closed.** If the backend is missing (`bwrap` not installed,
|
|
327
|
+
non-darwin/linux), every shell call returns exit `127` with the reason and
|
|
328
|
+
`execStream` / `execBackground` throw; nothing runs unsandboxed. Probed once
|
|
329
|
+
at context creation; `capabilities.isolated` is `true` only when isolation is
|
|
330
|
+
actually enforced (requested AND backend available), `false` when it was
|
|
331
|
+
requested but the context is in this fail-closed state.
|
|
332
|
+
|
|
333
|
+
**Denials.** A failed command whose stderr matches `Operation not permitted`
|
|
334
|
+
/ `Read-only file system` gets one appended `[sandbox] …` line naming the
|
|
335
|
+
writable roots and the settings that widen them, so the model asks instead
|
|
336
|
+
of guessing. Process-group kill semantics are unchanged: `sandbox-exec`
|
|
337
|
+
execs the shell in place and `bwrap` runs without `--new-session`.
|
|
338
|
+
|
|
339
|
+
In the chat hosts this is `Settings.sandbox` / `sandboxNetwork` /
|
|
340
|
+
`sandboxAllowWrite` (see `docs/CHAT.md`). Docker / e2b / daytona contexts
|
|
341
|
+
ignore it — they are already isolated.
|
|
281
342
|
|
|
282
343
|
The process context also implements the optional `fileSize` capability — a
|
|
283
344
|
containment-aware size probe that lets whole-file tools (`read_file`, `edit`,
|
package/docs/INTERACTIONS.md
CHANGED
|
@@ -87,7 +87,10 @@ user's own selection rather than resetting it.
|
|
|
87
87
|
Response shape:
|
|
88
88
|
|
|
89
89
|
```json
|
|
90
|
-
{
|
|
90
|
+
{
|
|
91
|
+
"answers": { "name": "Jane", "notes": "...", "fw": "react", "go": true },
|
|
92
|
+
"instructions": "Also keep the old endpoint alive until the migration lands."
|
|
93
|
+
}
|
|
91
94
|
```
|
|
92
95
|
|
|
93
96
|
Missing keys = question was skipped (only possible when `required:
|
|
@@ -95,12 +98,21 @@ false`). Empty-string answers and empty multi-select picks are dropped
|
|
|
95
98
|
at serialization; a multi-select (`type: 'select'`, `multi: true`)
|
|
96
99
|
answers as an array of choice ids.
|
|
97
100
|
|
|
101
|
+
`instructions` is free text the user attached to the whole form. Every
|
|
102
|
+
surface offers it unconditionally (the TUI wizard ends on an "additional
|
|
103
|
+
instructions" step, the GUI modal has a permanent textarea under the
|
|
104
|
+
questions), so the user can always refine or override the questions
|
|
105
|
+
instead of being boxed into the model's choices. Omitted when left empty.
|
|
106
|
+
The tool description tells the model it is authoritative.
|
|
107
|
+
|
|
98
108
|
## Keyboard
|
|
99
109
|
|
|
100
110
|
In the question wizard (multi-question batches):
|
|
101
111
|
|
|
102
112
|
- `↑/↓` (or `j/k`) — navigate options
|
|
103
|
-
- `↵` — submit the active question / pick the focused option
|
|
113
|
+
- `↵` — submit the active question / pick the focused option. The last
|
|
114
|
+
step is always "additional instructions" (optional textarea): `↵` on an
|
|
115
|
+
empty box sends the answers as they are.
|
|
104
116
|
- `space` — toggle the focused option (multi-selects only; `↵` submits
|
|
105
117
|
the whole selection, at least one pick required unless `required: false`)
|
|
106
118
|
- `shift+↹` — back one question (preserves your answers, pre-fills the
|
package/docs/SKILL.md
CHANGED
|
@@ -49,6 +49,7 @@ const agent = createAgent({
|
|
|
49
49
|
toolBudgets: { run_query: { max: 20, onExceed: 'steer' } },
|
|
50
50
|
compactStrategy: 'off', // 'off' | 'tail' (non-Anthropic compaction)
|
|
51
51
|
compactThreshold: 131_072, // 128 KiB
|
|
52
|
+
compactThresholdWindowFraction: 0.25, // raise it to 25% of the model's window (large-context runs stop re-billing the prefix)
|
|
52
53
|
compactKeepTurns: 4,
|
|
53
54
|
toolDisclosure: 'eager', // 'eager' | 'lazy'
|
|
54
55
|
toolSearch: { limit: 20 },
|
|
@@ -182,6 +183,32 @@ Flatten via `toolResultToText(result)`. MCP image blocks are auto-normalized via
|
|
|
182
183
|
|
|
183
184
|
Cache hits surface on `TurnUsage.cacheRead` / `cacheCreation`. Anthropic + OpenRouter populate them per turn. Live break/drift telemetry is a hook concern — see `cache:break` / `cache:drift` in the [Hook reference](#hook-reference).
|
|
184
185
|
|
|
186
|
+
### Preserved thinking (Anthropic)
|
|
187
|
+
|
|
188
|
+
Claude Fable 5.1 and later bind every replayed `thinking` block to the exact prefix it was produced under — `system`, `tools`, and every earlier message. If any of those bytes changed since, that block and every later one are invalid. By default the API rejects the whole request with a 400; on accounts created after 2026-08-31 this is enforced out of the box, on older accounts only when the field below is set. (`platform.claude.com/docs/en/build-with-claude/preserved-thinking`)
|
|
189
|
+
|
|
190
|
+
Zidane opts into the safe behavior on every thinking-enabled Anthropic request: `thinking.block_binding.prefix_mismatch_behavior: "drop_block"` plus the `thinking-binding-controls-2026-08-01` beta. Invalid blocks are dropped server-side (unbilled), the request succeeds, and history is never mutated. Thinking-off requests and Bedrock are untouched.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
anthropic({ apiKey: 'sk-ant-...', thinkingBinding: 'drop_block' }) // default
|
|
194
|
+
anthropic({ apiKey: 'sk-ant-...', thinkingBinding: 'error' }) // fail the run on a prefix edit — debugging / CI
|
|
195
|
+
anthropic({ apiKey: 'sk-ant-...', thinkingBinding: 'off' }) // send nothing; pre-feature wire bytes, account default applies
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Precedence: `thinkingBinding` param > shell `ZIDANE_THINKING_BINDING` > chat setting `thinkingBinding` (published on `ZIDANE_THINKING_BINDING_SETTING` before each run by the TUI / daemon) > `'drop_block'`. Read per request, so a flip lands on the next call without rebuilding the provider. The setting is labelled "Preserved thinking (Anthropic only)" and is inert on every other provider.
|
|
199
|
+
|
|
200
|
+
Effect per mode:
|
|
201
|
+
|
|
202
|
+
| Mode | On a prefix edit | History | Visible as |
|
|
203
|
+
|---|---|---|---|
|
|
204
|
+
| `drop_block` | Stale blocks dropped server-side; model answers without that reasoning; cache restarts at the edit | untouched | `provider:input-transformations` (`prefixMismatches` / `modelMismatches`) |
|
|
205
|
+
| `error` | 400; the run rejects, no retry | untouched | run error `Invalid \`signature\` in \`thinking\` block … bound to a different conversation` |
|
|
206
|
+
| `off` | Account default: old accounts tolerate, new accounts 400 → the signature-scrub ladder strips **all** history thinking and retries | scrubbed on 400 | `history:repair` |
|
|
207
|
+
|
|
208
|
+
What zidane already keeps prefix-safe: append-only turns, nudges and stale-read notices, tail truncation, compaction (`applyCompactSummaryCutoff` strips thinking from the kept tail), the `__output__` structured-output call, lazy MCP disclosure (defaults to `toolSearch.mode: 'dispatch'` on Anthropic so `tools` stays byte-stable), the TUI `<env> Date:` (pinned per session). What still costs reasoning once per edit: rewriting `system` between turns (cwd change, interaction-mode flip, rules-file edit, skill activation), a run-level `tools` change, `elideStaleReads: 'stub'`, `compactStrategy: 'tail'`, `mediaKeepTurns`. A model downgrade mid-conversation drops the newer model's blocks with `model_binding_mismatch`; that is not an edit and needs no action. Every `cache:break` attributed to `system`, `tools` or `messagePrefix` is also a preserved-thinking drop, so wire the two hooks to the same telemetry.
|
|
209
|
+
|
|
210
|
+
Live coverage: `test-inference/preserved-thinking.inference.test.ts`.
|
|
211
|
+
|
|
185
212
|
### Provider error classification
|
|
186
213
|
|
|
187
214
|
Provider failures are wrapped via `toTypedError(err)` before leaving `agent.run()` — each provider implements `Provider.classifyError(err): ClassifiedError | null`; unrecognized errors fall back to `AgentProviderError`. Aborts always produce `AgentAbortedError`. Match on `instanceof`, not on `err.message`.
|
|
@@ -339,6 +366,7 @@ Every event in `AgentHooks` (`src/agent.ts`), one row each. `child:*` bubble eve
|
|
|
339
366
|
| `compact:progress` | Throttled, while the compaction summary streams | — | `+ estOutputTokens` |
|
|
340
367
|
| `compact:end` | Exactly once per `compact:start`, on success or failure | — | `+ status: 'success' \| 'error'` (success: replaced/dropped/restored counts + `effectiveTokens`; error: `error`) |
|
|
341
368
|
| `history:repair` | After a provider stream settles when the loop scrubbed provider-rejected reasoning state (e.g. Anthropic signature-400 poisoning) | — | `reason: 'invalid-anthropic-thinking-signature', runId, sessionId?, turnIds, removedBlocks` |
|
|
369
|
+
| `provider:input-transformations` | Provider dropped replayed thinking blocks server-side before sampling (Anthropic preserved-thinking binding, `input_transformations`). History untouched; `prefix_binding_mismatch` entries mean this host edited system/tools/an earlier message | — | `runId, turnId, sessionId?, transformations[{type,path,reason}], prefixMismatches, modelMismatches` |
|
|
342
370
|
| `oauth:refresh` | OAuth token refreshed | — | `provider, providerId, source: 'params'\|'file', previousCredentials, credentials` |
|
|
343
371
|
| `content-ref:resolve` | Wire assembly sees a block carrying `ref`; resolves persisted content refs into provider-bound bytes | **yes** (`data`) | `block, data?, childId?, depth?` |
|
|
344
372
|
| `tool:gate` | Before each tool call | **yes** (`block, reason, result?`) | `turnId, callId, name, displayName, input, runToolCounts` — `block` refuses with `tool_result.content = "Blocked: <reason>"` + `is_error: true`; `result` substitutes and skips execute; `block` wins over `result` |
|
|
@@ -688,7 +716,9 @@ createAgent({
|
|
|
688
716
|
|
|
689
717
|
The system prompt gains a `<searchable_tools>` block. `tool_search({ query, names, server, limit })` returns matching schemas and unlocks them for the rest of the run. A `tool:gate` middleware refuses un-surfaced lazy tools. Catalog + search results show the **wire** name; the unlock set keys on canonical so dispatch / `session.turns` stay alias-stable.
|
|
690
718
|
|
|
691
|
-
`behavior.toolSearch` knobs (no-op in eager mode): `tool: false` opts out of auto-injection; `limit: 20` caps default results. Per-server `disclosure: 'eager' | 'lazy'` overrides the agent default; run-level overrides agent-level.
|
|
719
|
+
`behavior.toolSearch` knobs (no-op in eager mode): `tool: false` opts out of auto-injection; `limit: 20` caps default results; `mode: 'unlock' | 'dispatch'` picks how a surfaced tool becomes callable. Per-server `disclosure: 'eager' | 'lazy'` overrides the agent default; run-level overrides agent-level.
|
|
720
|
+
|
|
721
|
+
Cost: in `'unlock'` mode (default) every discovery wave grows the tools array, and since providers hash `tools → system → messages` that is a **full** prompt-cache rewrite each time. `'dispatch'` mode keeps the tools array byte-stable: a fixed `call_tool { name, arguments }` native tool is added, surfaced tools are invoked through it, and the loop unwraps the envelope before dispatch so gating, schema validation (against the inner tool), hooks and transcript events see the inner tool exactly as a direct call. Chat hosts expose it as `Settings.stableToolList`.
|
|
692
722
|
|
|
693
723
|
## Skills
|
|
694
724
|
|
package/docs/TUI.md
CHANGED
|
@@ -108,7 +108,7 @@ Not re-exported: the renderer-agnostic engine (settings, theme, safe-mode, store
|
|
|
108
108
|
Layered slots, in priority order:
|
|
109
109
|
|
|
110
110
|
1. **Transcript-slot takeover** — a file-edit approval (`edit`/`multi_edit`/`write_file`) renders `FileEditApprovalModal` inline in the transcript slot (`<Transcript visible={!fileEditPending}>` so scroll position and memoized turn anchors survive open→close). See [File-edit approval modal](#file-edit-approval-modal).
|
|
111
|
-
2. **Bottom slot**, one of: non-file-edit `pendingApproval` → `ApprovalBlock` (accept once / for session / + remember / deny, esc aborts the run) · `pendingInteraction` → `InteractionBlock` (plan picker or Q&A wizard; esc aborts if live,
|
|
111
|
+
2. **Bottom slot**, one of: non-file-edit `pendingApproval` → `ApprovalBlock` (accept once / for session / + remember / deny, `ctrl+esc` aborts the run) · `pendingInteraction` → `InteractionBlock` (plan picker or Q&A wizard; `ctrl+esc` aborts if live, esc leaves for the sessions list) · else `PromptBlock` (textarea + history), kept mounted (`Display.None` when hidden) so draft/cursor/attachments survive an approval round-trip.
|
|
112
112
|
|
|
113
113
|
When the queue has entries, a `QueuedMessagesBlock` renders between transcript and prompt:
|
|
114
114
|
|
|
@@ -140,7 +140,7 @@ Every action routes through `<userDir>/keybindings.json`, matched via `matchesBi
|
|
|
140
140
|
| `ctrl+shift+m` | `openMainSession` | any, when `Settings.orchestration` is on | jump to (or lazily create) the pinned Main orchestration session for the cwd; requires the daemon runtime. Silent no-op when the setting/runtime is off |
|
|
141
141
|
| `ctrl+p` | `openUsagePanel` | chat | subscription usage panel; also opens by clicking the footer's `▰ 5h 43%` segment |
|
|
142
142
|
| `ctrl+y` | `openKeybindings` | non-auth | keybindings panel, `↵` opens `keybindings.json` |
|
|
143
|
-
| `ctrl+k` | `cancelToolCall` | chat (busy, ≥1 in-flight call) | cancel-tool picker (`agent.cancelTool(callId)`); distinct from `esc` (whole-run abort) |
|
|
143
|
+
| `ctrl+k` | `cancelToolCall` | chat (busy, ≥1 in-flight call) | cancel-tool picker (`agent.cancelTool(callId)`); distinct from `ctrl+esc` (whole-run abort) |
|
|
144
144
|
| `ctrl+h` | `changeCwd` | non-auth | open the directory picker to change cwd |
|
|
145
145
|
| `ctrl+v` | `attachClipboardImage` | textarea | paste text or an image from the OS clipboard, read by the process itself (bypasses a frozen terminal paste path) |
|
|
146
146
|
| `ctrl+g` | `openExternalEditor` | textarea | edit the prompt draft in `$EDITOR`/`$VISUAL`; gated on `externalEditor` setting |
|
|
@@ -151,7 +151,8 @@ Every action routes through `<userDir>/keybindings.json`, matched via `matchesBi
|
|
|
151
151
|
| — (unbound) | `enterQueueSelection` | textarea | move focus into the queue box |
|
|
152
152
|
| `enter` / `shift+enter` | — | textarea | submit / newline |
|
|
153
153
|
| `↑`/`↓` at buffer edges | — | textarea (popup closed) | cycle prompt history |
|
|
154
|
-
| `esc` |
|
|
154
|
+
| `ctrl+esc` | `abortRun` | chat (busy or pending approval) | abort run + drain approval+interaction queues. Rebind (e.g. `ctrl+x`) if the terminal cannot report ctrl on esc |
|
|
155
|
+
| `esc` | — | popup / chat / modal open | dismiss popup, or leave the chat for the sessions list (busy or not — the run continues), or close modal |
|
|
155
156
|
| `pageup`/`pagedown`, `shift+pageup`/`shift+pagedown` | — | chat, no modal | scroll transcript one page / jump to top-bottom |
|
|
156
157
|
| `ctrl+a` | (textarea built-in) | textarea | select-all |
|
|
157
158
|
|
|
@@ -176,7 +177,7 @@ Every action routes through `<userDir>/keybindings.json`, matched via `matchesBi
|
|
|
176
177
|
|
|
177
178
|
`<userDir>/keybindings.json` is JSONC. `ensureKeybindingsFile` never overwrites an existing file. Invalid/unknown entries silently fall back to defaults (`ZIDANE_DEBUG` logs why). Settings → General → "Keybindings" opens the file in `$EDITOR`/`$VISUAL`; changes apply on restart. Full alias/parsing rules: [CHAT.md § Keybindings](./CHAT.md#keybindings).
|
|
178
179
|
|
|
179
|
-
**
|
|
180
|
+
**Abort semantics.** `abortRun` (`ctrl+esc`) runs `denyAll → interactions.cancelAll → abort → stream.reset → agent.destroy` (shared with session-switching/re-auth teardown). `applyGate` does **not** cascade a single deny through the rest of the queue: denying one approval blocks only that call (`Blocked: …`), other pending approvals stay queued. The global `abortRun` is the only path that denies everything + aborts the run. Plain `esc` never aborts: under the daemon a window can reattach to a session mid-run, and esc must always be able to return to the sessions list. Local runtime only: picking another session (or new) while a run is in flight is refused with a notice under the list — the window's single agent would otherwise be torn down by `activateSession`; abort first, or run under the daemon where runs outlive the window's session choice. Esc is consumed by the completion popup first when one is open.
|
|
180
181
|
|
|
181
182
|
## Modals
|
|
182
183
|
|
|
@@ -199,7 +200,7 @@ Inline-mounted in `ChatScreen`'s transcript slot (not stacked); keyed on `reques
|
|
|
199
200
|
|
|
200
201
|
### Tool-call cancellation
|
|
201
202
|
|
|
202
|
-
`CancelToolModal` lists the in-flight tool registry (`App.tsx` tracks it via `tool:before`/`tool:after`/`tool:error`/`tool:cancelled`, mirrored for `child:*`), opened by `ctrl+k` when `busy && !pendingApproval && inFlightTools.length > 0`. Row: `›` cursor, tool name, truncated `callId`, optional `· child-N`, elapsed time. `↑`/`↓` navigate, `↵` cancels the focused row, `a` cancels every call, `esc` dismisses. Auto-dismisses 500ms after the in-flight list empties. Cancellation resolves that call with `TOOL_USE_CANCELLED_MESSAGE` (`isError: true`); other in-flight tools keep running — distinct from the run-wide `esc abort
|
|
203
|
+
`CancelToolModal` lists the in-flight tool registry (`App.tsx` tracks it via `tool:before`/`tool:after`/`tool:error`/`tool:cancelled`, mirrored for `child:*`), opened by `ctrl+k` when `busy && !pendingApproval && inFlightTools.length > 0`. Row: `›` cursor, tool name, truncated `callId`, optional `· child-N`, elapsed time. `↑`/`↓` navigate, `↵` cancels the focused row, `a` cancels every call, `esc` dismisses. Auto-dismisses 500ms after the in-flight list empties. Cancellation resolves that call with `TOOL_USE_CANCELLED_MESSAGE` (`isError: true`); other in-flight tools keep running — distinct from the run-wide `ctrl+esc` abort.
|
|
203
204
|
|
|
204
205
|
### TodosModal
|
|
205
206
|
|