mixdog 0.9.17 → 0.9.19
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/package.json +3 -2
- package/scripts/build-runtime-windows.ps1 +242 -242
- package/scripts/output-style-smoke.mjs +2 -2
- package/scripts/recall-bench-cases.json +11 -0
- package/scripts/recall-bench.mjs +91 -2
- package/scripts/recall-usecase-cases.json +1 -1
- package/scripts/smoke-runtime-negative.ps1 +106 -106
- package/scripts/tool-efficiency-diag.mjs +5 -2
- package/scripts/tool-smoke.mjs +101 -27
- package/src/agents/debugger/AGENT.md +3 -3
- package/src/agents/heavy-worker/AGENT.md +7 -10
- package/src/agents/maintainer/AGENT.md +1 -2
- package/src/agents/reviewer/AGENT.md +1 -2
- package/src/agents/worker/AGENT.md +5 -8
- package/src/defaults/agents.json +3 -0
- package/src/mixdog-session-runtime.mjs +23 -6
- package/src/rules/agent/00-core.md +4 -3
- package/src/rules/agent/30-explorer.md +53 -22
- package/src/rules/lead/02-channels.md +3 -3
- package/src/rules/lead/lead-tool.md +3 -2
- package/src/rules/shared/01-tool.md +24 -29
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +24 -3
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +250 -35
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +198 -6
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +10 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +13 -15
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +45 -3
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +195 -3
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +1 -1
- package/src/runtime/channels/backends/discord-attachments.mjs +2 -2
- package/src/runtime/channels/backends/discord-gateway.mjs +26 -3
- package/src/runtime/channels/backends/discord.mjs +139 -7
- package/src/runtime/channels/index.mjs +290 -76
- package/src/runtime/channels/lib/crash-log.mjs +21 -3
- package/src/runtime/channels/lib/inbound-routing.mjs +19 -12
- package/src/runtime/channels/lib/memory-client.mjs +32 -14
- package/src/runtime/channels/lib/output-forwarder.mjs +156 -14
- package/src/runtime/channels/lib/owner-heartbeat.mjs +13 -4
- package/src/runtime/channels/lib/runtime-paths.mjs +48 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +17 -7
- package/src/runtime/channels/lib/voice-transcription.mjs +4 -2
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +8 -2
- package/src/runtime/memory/lib/memory-recall-store.mjs +182 -9
- package/src/runtime/memory/lib/query-handlers.mjs +36 -4
- package/src/runtime/memory/lib/recall-format.mjs +106 -6
- package/src/runtime/memory/lib/session-ingest.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +10 -4
- package/src/runtime/shared/background-tasks.mjs +4 -2
- package/src/runtime/shared/tool-execution-contract.mjs +1 -1
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +30 -1
- package/src/session-runtime/config-lifecycle.mjs +1 -1
- package/src/session-runtime/cwd-plugins.mjs +46 -3
- package/src/session-runtime/mcp-glue.mjs +24 -3
- package/src/session-runtime/output-styles.mjs +44 -10
- package/src/session-runtime/workflow.mjs +16 -1
- package/src/standalone/channel-worker.mjs +88 -7
- package/src/standalone/explore-tool.mjs +1 -1
- package/src/tui/App.jsx +57 -77
- package/src/tui/app/channel-pickers.mjs +45 -0
- package/src/tui/app/slash-commands.mjs +0 -1
- package/src/tui/app/slash-dispatch.mjs +0 -16
- package/src/tui/app/transcript-window.mjs +66 -1
- package/src/tui/app/use-mouse-input.mjs +9 -2
- package/src/tui/app/use-prompt-handlers.mjs +7 -94
- package/src/tui/app/use-transcript-scroll.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +74 -8
- package/src/tui/components/PromptInput.jsx +33 -64
- package/src/tui/components/ToolExecution.jsx +2 -2
- package/src/tui/dist/index.mjs +4744 -4806
- package/src/tui/engine.mjs +109 -20
- package/src/tui/lib/voice-setup.mjs +166 -0
- package/src/tui/paste-attachments.mjs +12 -5
- package/src/tui/prompt-history-store.mjs +125 -12
- package/scripts/bench/cache-probe-tasks.json +0 -8
- package/scripts/bench/lead-review-tasks-r3.json +0 -20
- package/scripts/bench/lead-review-tasks.json +0 -20
- package/scripts/bench/r4-mixed-tasks.json +0 -20
- package/scripts/bench/r5-orchestrated-task.json +0 -7
- package/scripts/bench/review-tasks.json +0 -20
- package/scripts/bench/round-codex.json +0 -114
- package/scripts/bench/round-mixdog-lead-r3.json +0 -269
- package/scripts/bench/round-mixdog-lead.json +0 -269
- package/scripts/bench/round-mixdog.json +0 -126
- package/scripts/bench/round-r10-bigsample.json +0 -679
- package/scripts/bench/round-r11-codexalign.json +0 -257
- package/scripts/bench/round-r13-clientmeta.json +0 -464
- package/scripts/bench/round-r14-betafeatures.json +0 -466
- package/scripts/bench/round-r15-fulldefault.json +0 -462
- package/scripts/bench/round-r16-sessionid.json +0 -466
- package/scripts/bench/round-r17-wirebytes.json +0 -456
- package/scripts/bench/round-r18-prewarm.json +0 -468
- package/scripts/bench/round-r19-clean.json +0 -472
- package/scripts/bench/round-r20-prewarm-clean.json +0 -475
- package/scripts/bench/round-r21-delta-retry.json +0 -473
- package/scripts/bench/round-r22-full-probe.json +0 -693
- package/scripts/bench/round-r23-itemprobe.json +0 -701
- package/scripts/bench/round-r24-shapefix.json +0 -677
- package/scripts/bench/round-r25-serial.json +0 -464
- package/scripts/bench/round-r26-parallel3.json +0 -671
- package/scripts/bench/round-r27-parallel10.json +0 -894
- package/scripts/bench/round-r28-parallel10-stagger.json +0 -882
- package/scripts/bench/round-r29-parallel10-stagger166.json +0 -886
- package/scripts/bench/round-r30-instid.json +0 -253
- package/scripts/bench/round-r31-upgradeprobe.json +0 -256
- package/scripts/bench/round-r32-vs-codex-lead.json +0 -254
- package/scripts/bench/round-r33-vs-codex-codex.json +0 -115
- package/scripts/bench/round-r34-orchestrated.json +0 -120
- package/scripts/bench/round-r35-orchestrated-codex.json +0 -61
- package/scripts/bench/round-r36-orchestrated-capped.json +0 -128
- package/scripts/bench/round-r4-codex.json +0 -114
- package/scripts/bench/round-r4-mixed.json +0 -225
- package/scripts/bench/round-r5-gpt-lead.json +0 -259
- package/scripts/bench/round-r6-codex.json +0 -114
- package/scripts/bench/round-r6-solo.json +0 -257
- package/scripts/bench/round-r7-full.json +0 -254
- package/scripts/bench/round-r8-fulldefault.json +0 -255
- package/src/tui/components/prompt-input/voice-indicator.mjs +0 -39
- package/src/tui/lib/voice-recorder.mjs +0 -469
|
@@ -5,16 +5,13 @@ permission: read-write
|
|
|
5
5
|
# Heavy Worker
|
|
6
6
|
Broad implementation agent.
|
|
7
7
|
|
|
8
|
-
Bounded slices; smallest coherent change, not rewrite. Stop
|
|
9
|
-
|
|
8
|
+
Bounded slices; smallest coherent change, not rewrite. Stop when scope is
|
|
9
|
+
unclear or the blast radius grows.
|
|
10
10
|
|
|
11
|
-
EDIT-FIRST DISCIPLINE. Survey the slice with
|
|
12
|
-
patch the first bounded piece — edit incrementally, don't read
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
runtime reminder, patch the piece you understand or report blocked — a valid
|
|
16
|
-
completion. Self-check comes AFTER edits; deep verification is Lead's.
|
|
11
|
+
EDIT-FIRST DISCIPLINE. Survey the slice with one batched retrieval round,
|
|
12
|
+
then patch the first bounded piece — edit incrementally, don't read
|
|
13
|
+
exhaustively. Repeated read-only turns without an edit = stalling; on a
|
|
14
|
+
runtime reminder, patch the piece you understand or report blocked.
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
`file:line`; no narration or bloat.
|
|
16
|
+
Self-verify edits with shell (targeted test/build).
|
|
20
17
|
|
|
@@ -7,5 +7,4 @@ permission: read-write
|
|
|
7
7
|
Maintenance and cleanup agent.
|
|
8
8
|
|
|
9
9
|
Smallest coherent change; no scope growth. Repeated read-only turns without
|
|
10
|
-
an edit = stalling; patch or return blocked
|
|
11
|
-
completion. Hand off as fragments (`file:line`); no narration.
|
|
10
|
+
an edit = stalling; patch or return blocked.
|
|
@@ -8,5 +8,4 @@ Regression/risk review agent.
|
|
|
8
8
|
|
|
9
9
|
Find actionable correctness/regression/security/verification risks. Findings
|
|
10
10
|
first, severity-ordered, one line with `file:line`; skip non-risky nits. If
|
|
11
|
-
clean, one line + only material residual risk.
|
|
12
|
-
no report bloat.
|
|
11
|
+
clean, one line + only material residual risk.
|
|
@@ -7,13 +7,10 @@ Scoped implementation agent.
|
|
|
7
7
|
|
|
8
8
|
Smallest scoped change; no drive-by cleanup. Stop when done/blocked.
|
|
9
9
|
|
|
10
|
-
EDIT-FIRST DISCIPLINE. Brief anchors (`file:line`) are pre-verified — trust
|
|
11
|
-
patch. No anchor:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
runtime reminder, patch now or return blocked with what's missing — a blocked
|
|
15
|
-
report is a valid completion. Threshold is "plausible", not "proven";
|
|
16
|
-
self-check comes AFTER the edit, and Lead/Reviewer own final verification.
|
|
10
|
+
EDIT-FIRST DISCIPLINE. Brief anchors (`file:line`) are pre-verified — trust
|
|
11
|
+
and patch. No anchor: one locating batch, then `apply_patch`. Repeated
|
|
12
|
+
read-only turns without an edit = stalling; on a runtime reminder, patch now
|
|
13
|
+
or return blocked. Threshold is "plausible", not "proven".
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
Self-verify edits with shell (node --check/test).
|
|
19
16
|
|
package/src/defaults/agents.json
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
"description": "Filesystem navigation agent invoked by the `explore` MCP tool",
|
|
8
8
|
"invokedBy": "explore",
|
|
9
9
|
"toolSchemaProfile": "read",
|
|
10
|
+
"schemaAllowedTools": ["grep", "find", "glob", "code_graph"],
|
|
10
11
|
"kind": "retrieval",
|
|
11
12
|
"permission": "read",
|
|
12
13
|
"stallCap": { "idleSeconds": 240, "toolRunningSeconds": 180 }
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
"description": "Scheduled-task executor invoked by scheduler tick",
|
|
55
56
|
"invokedBy": "scheduler",
|
|
56
57
|
"toolSchemaProfile": "read-write-search",
|
|
58
|
+
"schemaAllowedTools": ["code_graph", "find", "glob", "list", "grep", "read", "apply_patch", "search", "web_fetch"],
|
|
57
59
|
"kind": "maintenance",
|
|
58
60
|
"permission": "read-write",
|
|
59
61
|
"inboundEvent": true,
|
|
@@ -67,6 +69,7 @@
|
|
|
67
69
|
"description": "Webhook payload handler invoked by inbound webhook events",
|
|
68
70
|
"invokedBy": "webhook",
|
|
69
71
|
"toolSchemaProfile": "read-write-search",
|
|
72
|
+
"schemaAllowedTools": ["code_graph", "find", "glob", "list", "grep", "read", "apply_patch", "search", "web_fetch"],
|
|
70
73
|
"kind": "maintenance",
|
|
71
74
|
"permission": "read-write",
|
|
72
75
|
"inboundEvent": true,
|
|
@@ -315,7 +315,7 @@ async function profiledImport(label, spec, { optional = false } = {}) {
|
|
|
315
315
|
throw error;
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
-
const outputStyleStatus = (dataDir = STANDALONE_DATA_DIR) => outputStyleStatusRaw(STANDALONE_ROOT, dataDir || STANDALONE_DATA_DIR);
|
|
318
|
+
const outputStyleStatus = (dataDir = STANDALONE_DATA_DIR, opts = {}) => outputStyleStatusRaw(STANDALONE_ROOT, dataDir || STANDALONE_DATA_DIR, opts);
|
|
319
319
|
// Workflow/agent pack loaders bound to this runtime's root/data layout.
|
|
320
320
|
const {
|
|
321
321
|
listWorkflowPacks,
|
|
@@ -325,6 +325,7 @@ const {
|
|
|
325
325
|
activeWorkflowSummary,
|
|
326
326
|
loadAgentDefinition,
|
|
327
327
|
workflowContextBlock,
|
|
328
|
+
activeWorkflowContext,
|
|
328
329
|
} = createWorkflowHelpers({
|
|
329
330
|
rootDir: STANDALONE_ROOT,
|
|
330
331
|
dataDir: STANDALONE_DATA_DIR,
|
|
@@ -918,6 +919,16 @@ export async function createMixdogSessionRuntime({
|
|
|
918
919
|
stopRemote('superseded-by-newer-remote-session');
|
|
919
920
|
emitRemoteStateChange(false, 'superseded');
|
|
920
921
|
}
|
|
922
|
+
// Symmetric acquire: the worker took the bridge seat (boot make-before-
|
|
923
|
+
// break or activate). Flip remote ON via the same side-state a user
|
|
924
|
+
// /remote toggles — remoteEnabled + transcript writer — but WITHOUT
|
|
925
|
+
// re-invoking channel start (the worker is already running; startRemote
|
|
926
|
+
// would re-fork/activate). Idempotent: no-op when already enabled.
|
|
927
|
+
if (msg?.params?.state === 'acquired' && !remoteEnabled) {
|
|
928
|
+
remoteEnabled = true;
|
|
929
|
+
ensureRemoteTranscriptWriter();
|
|
930
|
+
emitRemoteStateChange(true, 'acquired');
|
|
931
|
+
}
|
|
921
932
|
return;
|
|
922
933
|
}
|
|
923
934
|
if (msg?.method !== 'notifications/claude/channel') return;
|
|
@@ -1339,18 +1350,24 @@ export async function createMixdogSessionRuntime({
|
|
|
1339
1350
|
await resolveMissingRouteModelForFirstTurn();
|
|
1340
1351
|
requireModelRoute();
|
|
1341
1352
|
bootProfile('session:create:route-ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
1342
|
-
|
|
1353
|
+
// refreshRouteEffort (effort/model-meta) and loadCoreMemoryContext (memory
|
|
1354
|
+
// files) are independent — refreshRouteEffort only touches route effort/
|
|
1355
|
+
// display fields, never provider/model that the memory load reads — so run
|
|
1356
|
+
// them concurrently instead of serially on the boot path.
|
|
1357
|
+
const [, coreMemoryContext] = await Promise.all([
|
|
1358
|
+
refreshRouteEffort(),
|
|
1359
|
+
loadCoreMemoryContext(),
|
|
1360
|
+
]);
|
|
1343
1361
|
bootProfile('session:create:effort-ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
1344
1362
|
const providerImpl = reg.getProvider(route.provider);
|
|
1345
1363
|
if (!providerImpl) {
|
|
1346
1364
|
throw new Error(`Provider "${route.provider}" is not configured.`);
|
|
1347
1365
|
}
|
|
1348
1366
|
bootProfile('session:create:provider-ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
1349
|
-
const coreMemoryContext = await loadCoreMemoryContext();
|
|
1350
1367
|
if (closeRequested) throw new Error('runtime is closing');
|
|
1351
1368
|
const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
|
|
1352
|
-
|
|
1353
|
-
const workflowContext =
|
|
1369
|
+
// Load the active WORKFLOW.md pack once for both summary + context block.
|
|
1370
|
+
const { summary: workflow, context: workflowContext } = activeWorkflowContext(config, dataDir);
|
|
1354
1371
|
const sessionOpts = {
|
|
1355
1372
|
provider: route.provider,
|
|
1356
1373
|
model: route.model,
|
|
@@ -2991,7 +3008,7 @@ export async function createMixdogSessionRuntime({
|
|
|
2991
3008
|
let selectedRoute = resolveRoute(config, requested);
|
|
2992
3009
|
await reg.initProviders(ensureProviderEnabled(config, selectedRoute.provider));
|
|
2993
3010
|
const modelMeta = await lookupModelMeta(selectedRoute.provider, selectedRoute.model);
|
|
2994
|
-
// Guard (A
|
|
3011
|
+
// Guard (option A / strict reject): a free-text string must never become the
|
|
2995
3012
|
// lead model. When the caller did not pin a provider, the route did not
|
|
2996
3013
|
// match a preset, and the model is unknown to both the live provider
|
|
2997
3014
|
// catalog (modelMeta is still the {id,provider} placeholder) and the
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# Agent Constraints
|
|
2
2
|
|
|
3
3
|
- Use English for agent task communication.
|
|
4
|
-
- ONE TURN = ONE BATCH:
|
|
5
|
-
turn
|
|
6
|
-
wasted round-trip.
|
|
4
|
+
- ONE TURN = ONE BATCH: a read-only call that could have ridden the prior
|
|
5
|
+
turn is a wasted round-trip.
|
|
7
6
|
- NEVER PREAMBLE: no status/progress narration, "I will..." setup, or any text
|
|
8
7
|
before tool calls — call needed tools immediately; emit text only for the
|
|
9
8
|
final handoff after tool work is done.
|
|
@@ -15,6 +14,8 @@
|
|
|
15
14
|
searched); state only what changed and where to look. Verification =
|
|
16
15
|
command + result in one line. Same fact twice = delete one.
|
|
17
16
|
- Handoff cap ~30 lines unless `Deliver:` raises it — a ceiling, not a target.
|
|
17
|
+
- A blocked or partial report is a valid completion: state done/missing/
|
|
18
|
+
blocker in fragments — never keep retrieving to avoid reporting.
|
|
18
19
|
- Banned as pure cost: report headings, markdown tables (unless requested),
|
|
19
20
|
prose narration, raw logs/tool traces, speculative next-checks, restated
|
|
20
21
|
brief, articles/politeness.
|
|
@@ -8,27 +8,58 @@ kind: retrieval
|
|
|
8
8
|
|
|
9
9
|
Coordinate locator. Deliverable = WHERE as `path:line`, never WHY — no
|
|
10
10
|
explaining or tracing. You ARE the `explore` tool: never call it; shared
|
|
11
|
-
rules pointing at `explore` don't apply
|
|
12
|
-
|
|
11
|
+
rules pointing at `explore` don't apply.
|
|
12
|
+
|
|
13
|
+
Tools: grep/find/glob/code_graph ONLY. `read` and `list` are FORBIDDEN —
|
|
14
|
+
grep match lines already carry every `path:line` you may output; opening a
|
|
15
|
+
file to "confirm" or "understand" a hit is the WHY you must not answer.
|
|
16
|
+
This ban has NO exception: not after a hit, not for the reason field, not
|
|
17
|
+
"just one read" — a `read`/`list` call anywhere in the session is a defect.
|
|
18
|
+
|
|
19
|
+
Turn 1 is the whole search, ONE message: one grep whose `pattern[]` packs
|
|
20
|
+
3-6 token variants (camelCase/kebab-case/snake_case/SCREAMING_SNAKE casings,
|
|
21
|
+
synonyms, library/domain names), plus `find` with name fragments, plus `code_graph`
|
|
22
|
+
symbol_search when the query names an identifier. A single-pattern,
|
|
23
|
+
single-tool first turn is a defect.
|
|
24
|
+
|
|
25
|
+
Search tokens are CODE tokens: first translate natural-language or
|
|
26
|
+
non-English queries into probable English identifiers (e.g. "최대 루프 반복
|
|
27
|
+
횟수" → maxLoop, loop-policy, iterations). Grep non-ASCII text only when
|
|
28
|
+
the query quotes a literal string.
|
|
29
|
+
|
|
30
|
+
Search scope is ALWAYS the session working directory: omit `path` (default
|
|
31
|
+
scope) or pass ONLY a path that appeared in an earlier result this session.
|
|
32
|
+
Inventing a directory (`/workspace/...`, guessed `src/lib`, another repo's
|
|
33
|
+
layout) is a defect — those results are always empty; on zero hits change
|
|
34
|
+
TOKENS, never guess paths.
|
|
13
35
|
|
|
14
36
|
Credibility is mechanical: hit = line/path contains ANY query token or
|
|
15
|
-
obvious synonym
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
No third branch: "hits exist but I want better
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
obvious synonym — never judge "is this the real implementation". Sole
|
|
38
|
+
exception: a generic-word-only match (schema, handler, config, resolver…)
|
|
39
|
+
with no SPECIFIC query token (product/library/domain name) = zero, not a hit.
|
|
40
|
+
A `code_graph` symbol hit (find_symbol/symbol_search returning `path:line`)
|
|
41
|
+
IS an anchor — emit it directly; never re-locate it with grep.
|
|
42
|
+
|
|
43
|
+
Rule zero — after EVERY tool result: ≥1 `path:line` matching a query token
|
|
44
|
+
→ answer NOW with those coordinates, mark weak anchors `?`; zero → one more
|
|
45
|
+
batch if budget remains. No third branch: "hits exist but I want better
|
|
46
|
+
ones" IS branch one. Once ANY turn yields a matching line, the only legal
|
|
47
|
+
next output is the final answer text — every further tool call is a defect.
|
|
48
|
+
|
|
49
|
+
Turns: hard max 3, expected 1; start each tool message with `turn N/3`.
|
|
50
|
+
Turns 2-3 are miss-recovery only (prior turn had ZERO matching lines) and
|
|
51
|
+
must change tokens OR scope, never reword.
|
|
52
|
+
Flow/how questions: first matching entry/definition anchors ARE the answer,
|
|
53
|
+
one anchor per concept — never trace the chain.
|
|
54
|
+
Compound queries ("where is X and what value/default does it use"): the
|
|
55
|
+
definition anchor answers BOTH parts — never launch extra searches for the
|
|
56
|
+
value, threshold, or content; one anchor per concept, all from the same batch.
|
|
57
|
+
|
|
58
|
+
Answer, nothing else: anchor lines `path:line — symbol — short reason`
|
|
59
|
+
(`?` if weak), max 3 lines — extra anchors are cost, not quality; pick the
|
|
60
|
+
3 with the most specific token match. Or `EXPLORATION_FAILED` — only after
|
|
61
|
+
the turn budget is
|
|
62
|
+
spent with zero anchors, or when every anchor matches only generic words.
|
|
63
|
+
Before emitting `EXPLORATION_FAILED`, re-scan ALL earlier tool results: if
|
|
64
|
+
any line anywhere matched a specific query token, answer with that anchor
|
|
65
|
+
(`?` if weak) instead — a weak anchor beats a false miss.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
# Channels
|
|
2
|
-
|
|
3
|
-
- Channel features are handled by the runtime.
|
|
1
|
+
# Channels
|
|
2
|
+
|
|
3
|
+
- Channel features are handled by the runtime.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Lead Tool Use
|
|
2
2
|
|
|
3
|
-
-
|
|
4
|
-
|
|
3
|
+
- Write-role agents run their own build/test verification via `shell`; Lead
|
|
4
|
+
runs cross-scope verification, benches, and everything git via `shell`
|
|
5
|
+
directly.
|
|
5
6
|
- Use the session's current project/workspace. Change the work project only
|
|
6
7
|
when the user asks for another project or a tool call needs another root.
|
|
7
8
|
- Use `agent` for scoped implementation, research, review, and debugging — not
|
|
@@ -1,32 +1,27 @@
|
|
|
1
1
|
# Tool Use
|
|
2
2
|
|
|
3
|
-
- Batch independent
|
|
4
|
-
prior result
|
|
5
|
-
|
|
6
|
-
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
the FIRST anchor ends the search — no verifying, ranking, or re-checking a
|
|
28
|
-
hit already on screen. When acting and looking are both possible, act.
|
|
29
|
-
- `read` uses `offset`/`limit` only; 2+ spans from known file(s) = ONE batched
|
|
30
|
-
`read` with `{path,offset,limit}` regions. Adjacent spans in one file
|
|
31
|
-
(within a few hundred lines) are ONE window, not repeated reads.
|
|
3
|
+
- Batch independent calls in one turn; serialize only when a call needs a
|
|
4
|
+
prior result. Merge equivalent variants/scopes into ONE call wherever the
|
|
5
|
+
schema accepts arrays (`pattern[]`, `path[]`, `symbols[]`, `query[]`).
|
|
6
|
+
- Route by what is already known: known symbol/relation → `code_graph`;
|
|
7
|
+
exact text in a known scope → `grep`; unknown location or concept-level
|
|
8
|
+
question → `explore`; name fragment → `find`; exact name pattern → `glob`;
|
|
9
|
+
known directory → `list`; known file/region → `read`.
|
|
10
|
+
- Valid anchors come from user input or tool output in this session; locate
|
|
11
|
+
anything else with `find` before `grep`/`read`. On ENOENT the next call is
|
|
12
|
+
`find` on the basename — never a retried guess.
|
|
13
|
+
- Retrieval stops when evidence covers the deliverable: single-answer tasks
|
|
14
|
+
end at the first sufficient anchor; enumeration tasks (review, audit) end
|
|
15
|
+
when the stated scope is covered. Never re-verify a hit already on screen;
|
|
16
|
+
a plausible anchor means the next call is the action itself
|
|
17
|
+
(patch/answer/handoff) — never "one more confirming read".
|
|
18
|
+
- Content-mode `grep` requests enough context (`-C`) to act without
|
|
19
|
+
re-reading the same file; bare match lines are existence checks only.
|
|
20
|
+
- Repeat a search concept only after a zero-result call, changing tokens or
|
|
21
|
+
scope — never wording alone.
|
|
22
|
+
- `read` windows use `offset`/`limit`; multiple spans or files = ONE call
|
|
23
|
+
with `{path,offset,limit}[]` regions. Size the window to the whole logical
|
|
24
|
+
unit (function/section) — over-read once instead of paging the same file
|
|
25
|
+
in small windows across turns; a 3rd window into one file means the first
|
|
26
|
+
should have been wider.
|
|
32
27
|
- Don't mix `apply_patch` with shell or other state-changing calls in one turn.
|
|
@@ -376,7 +376,7 @@ function toAnthropicMessages(messages) {
|
|
|
376
376
|
continue;
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
//
|
|
379
|
+
// First-party client parity: fold a user text turn that directly follows a
|
|
380
380
|
// tool_result turn into that tool_result's content. A sibling text
|
|
381
381
|
// turn after tool_result renders as `</function_results>\n\nHuman:`
|
|
382
382
|
// on the wire and trains the model toward 3-token empty end_turn
|
|
@@ -378,7 +378,7 @@ function toAnthropicMessages(messages) {
|
|
|
378
378
|
}
|
|
379
379
|
continue;
|
|
380
380
|
}
|
|
381
|
-
//
|
|
381
|
+
// First-party client parity: fold a user text turn that directly follows a
|
|
382
382
|
// tool_result turn into that tool_result's content (empty end_turn
|
|
383
383
|
// livelock prevention; see foldUserTextIntoToolResultTail).
|
|
384
384
|
if (m.role === 'user' && foldUserTextIntoToolResultTail(result, normalizeContentForAnthropic(m.content))) {
|
|
@@ -241,14 +241,35 @@ function windowFromPercent(label, value, source) {
|
|
|
241
241
|
return Object.keys(out).length > 2 ? out : null;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
// Grok Build billing periods are migrating from monthly to a shared weekly
|
|
245
|
+
// pool (xAI rollout is per-account). Derive the window cadence from the
|
|
246
|
+
// actual billing period length instead of hardcoding monthly: <=10 days
|
|
247
|
+
// means a weekly cycle, anything longer (or unknown) stays monthly.
|
|
248
|
+
function grokBillingCadence(config) {
|
|
249
|
+
if (config?.weeklyLimit !== undefined || config?.weekly_limit !== undefined) {
|
|
250
|
+
return { label: 'W', period: 'weekly' };
|
|
251
|
+
}
|
|
252
|
+
const start = resetAtMs(config?.billingPeriodStart ?? config?.billing_period_start);
|
|
253
|
+
const end = resetAtMs(config?.billingPeriodEnd ?? config?.billing_period_end);
|
|
254
|
+
if (start && end && end > start && (end - start) <= 10 * 24 * 60 * 60_000) {
|
|
255
|
+
return { label: 'W', period: 'weekly' };
|
|
256
|
+
}
|
|
257
|
+
return { label: 'M', period: 'monthly' };
|
|
258
|
+
}
|
|
259
|
+
|
|
244
260
|
function creditWindowFromBilling(config) {
|
|
245
261
|
if (!config || typeof config !== 'object') return null;
|
|
246
|
-
const limit = num(
|
|
262
|
+
const limit = num(
|
|
263
|
+
config.weeklyLimit?.val ?? config.weeklyLimit
|
|
264
|
+
?? config.monthlyLimit?.val ?? config.monthlyLimit
|
|
265
|
+
?? config.includedLimit?.val,
|
|
266
|
+
null,
|
|
267
|
+
);
|
|
247
268
|
const used = num(config.used?.val ?? config.includedUsed?.val ?? config.used, null);
|
|
248
269
|
if (limit === null || used === null || !(limit > 0)) return null;
|
|
249
270
|
const resetAt = resetAtMs(config.billingPeriodEnd ?? config.billing_period_end);
|
|
250
271
|
return {
|
|
251
|
-
label:
|
|
272
|
+
label: grokBillingCadence(config).label,
|
|
252
273
|
source: 'grok-build-billing',
|
|
253
274
|
usedPct: round(Math.min(100, used * 100 / limit), 2),
|
|
254
275
|
usedCredits: round(used, 2),
|
|
@@ -265,7 +286,7 @@ function balanceFromGrokBilling(config) {
|
|
|
265
286
|
if (cap === null || !(cap > 0)) return null;
|
|
266
287
|
return {
|
|
267
288
|
source: 'grok-build-on-demand',
|
|
268
|
-
period:
|
|
289
|
+
period: grokBillingCadence(config).period,
|
|
269
290
|
budgetCredits: round(cap, 2),
|
|
270
291
|
spentCredits: round(used, 2),
|
|
271
292
|
remainingCredits: round(Math.max(0, cap - used), 2),
|
|
@@ -29,15 +29,15 @@ import {
|
|
|
29
29
|
// 408 — request timeout
|
|
30
30
|
// 500/502/503/504 — server errors (overload / bad gateway / timeout)
|
|
31
31
|
// 429 is excluded from blanket transient retry, but withRetry() honors a
|
|
32
|
-
// SHORT Retry-After header (< SHORT_RETRY_AFTER_MAX_MS)
|
|
33
|
-
//
|
|
32
|
+
// SHORT Retry-After header (< SHORT_RETRY_AFTER_MAX_MS): a short-retry
|
|
33
|
+
// threshold of 20s matches first-party client behavior:
|
|
34
34
|
// brief throttle windows retry once the server-stated wait elapses; long or
|
|
35
35
|
// headerless 429s still surface immediately (quota windows are
|
|
36
36
|
// deterministic — sleeping into an outer watchdog just relabels the error).
|
|
37
37
|
const TRANSIENT_STATUSES = new Set([408, 500, 502, 503, 504])
|
|
38
38
|
|
|
39
39
|
// Max server-stated Retry-After we are willing to sleep on a 429 before
|
|
40
|
-
// surfacing it. Mirrors
|
|
40
|
+
// surfacing it. Mirrors the first-party client's 20s short-retry threshold.
|
|
41
41
|
const SHORT_RETRY_AFTER_MAX_MS = 20_000
|
|
42
42
|
|
|
43
43
|
// HTTP statuses that mean "permanent: stop retrying, surface to caller".
|
|
@@ -651,8 +651,8 @@ export function sanitizeAnthropicContentPairs(messages) {
|
|
|
651
651
|
|
|
652
652
|
/**
|
|
653
653
|
* Fold a plain user text turn into the trailing tool_result block of the
|
|
654
|
-
* previous user message (
|
|
655
|
-
*
|
|
654
|
+
* previous user message (first-party client parity: merge user content
|
|
655
|
+
* blocks into the trailing tool_result). Any sibling text after a
|
|
656
656
|
* tool_result renders as `</function_results>\n\nHuman:<...>` on the
|
|
657
657
|
* Anthropic wire; repeated mid-conversation this teaches the model to emit
|
|
658
658
|
* 3-token empty end_turn completions (upstream A/B sai-20260310-161901:
|