mixdog 0.9.103 → 0.9.105
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 +3 -4
- package/package.json +1 -1
- package/scripts/code-graph-description-contract.mjs +1 -1
- package/src/lib/rules-builder.cjs +7 -16
- package/src/output-styles/detailed.md +10 -14
- package/src/output-styles/extreme-minimal.md +5 -7
- package/src/output-styles/minimal.md +6 -7
- package/src/output-styles/simple.md +11 -12
- package/src/rules/agent/30-explorer.md +23 -22
- package/src/rules/lead/01-general.md +13 -14
- package/src/rules/lead/lead-tool.md +1 -1
- package/src/rules/shared/01-tool.md +36 -27
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +7 -14
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +33 -8
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +37 -5
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +8 -8
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +14 -9
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +39 -38
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -4
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +36 -4
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -3
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -6
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +22 -1
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +44 -14
- package/src/session-runtime/context-status.mjs +11 -5
- package/src/session-runtime/provider-request-snapshot.mjs +0 -2
- package/src/session-runtime/tool-catalog-data.mjs +13 -5
- package/src/session-runtime/tool-catalog-schema.mjs +7 -6
- package/src/session-runtime/tool-catalog.mjs +5 -5
- package/src/standalone/explore-tool.mjs +6 -12
- package/src/tui/app/usage-context-panels.mjs +5 -2
- package/src/tui/app/use-prompt-handlers.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +26 -12
- package/src/tui/components/ContextPanel.jsx +2 -0
- package/src/tui/components/PromptInput.jsx +9 -1
- package/src/tui/components/prompt-input/escape-policy.mjs +4 -4
- package/src/tui/components/prompt-input/restore-policy.mjs +35 -3
- package/src/tui/dist/index.mjs +111 -78
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ every number above live under `benchmarks/terminal-bench-2.1/`.
|
|
|
103
103
|
role mode for scripting.
|
|
104
104
|
- Mixdog Desktop: a full agent workbench for Windows/macOS/Linux (see
|
|
105
105
|
below).
|
|
106
|
-
-
|
|
106
|
+
- Installable web app over relay pairing — scan a QR code to open your
|
|
107
107
|
running sessions in a phone browser and keep going from any network.
|
|
108
108
|
- Optional Discord/Telegram channels, webhook endpoints, and cron schedules
|
|
109
109
|
with quiet hours for remote/event-driven workflows; channel voice messages
|
|
@@ -246,7 +246,7 @@ wizard covers first-run setup. For development run `npm run dev` inside
|
|
|
246
246
|
- **Automation** — visual editors for workflow and agent packs, cron
|
|
247
247
|
schedules, webhooks, and channel integrations.
|
|
248
248
|
- **Settings hub** — provider auth, capability sweep, git identity, and
|
|
249
|
-
QR device pairing for the web
|
|
249
|
+
QR device pairing for the installable web app, preloaded so every
|
|
250
250
|
category opens instantly.
|
|
251
251
|
|
|
252
252
|
## Scripts
|
|
@@ -302,8 +302,7 @@ src/
|
|
|
302
302
|
rules/ # Lead and agent instructions
|
|
303
303
|
apps/
|
|
304
304
|
desktop/ # Mixdog Desktop — Electron workbench (main/preload/renderer)
|
|
305
|
-
|
|
306
|
-
relay/ # relay server for remote/web/mobile access
|
|
305
|
+
relay/ # relay server for remote web-app access
|
|
307
306
|
scripts/
|
|
308
307
|
smoke*.mjs # smoke checks
|
|
309
308
|
*test.mjs # focused node:test checks
|
package/package.json
CHANGED
|
@@ -69,7 +69,7 @@ const CODE_GRAPH_DESCRIPTION_MUTATION_CORPUS = [
|
|
|
69
69
|
name: 'contracted negated file assignment',
|
|
70
70
|
mutate: (parts) => ({
|
|
71
71
|
...parts,
|
|
72
|
-
description: parts.description.replace(/file modes take files\[\]/i, "file modes aren't assigned files[]"),
|
|
72
|
+
description: parts.description.replace(/file modes (?:take|use) files\[\]/i, "file modes aren't assigned files[]"),
|
|
73
73
|
}),
|
|
74
74
|
},
|
|
75
75
|
{
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Source files (rules/):
|
|
21
21
|
* - shared/01-tool.md — universal tool policy (Lead + agent BP1, identical full set)
|
|
22
22
|
* - lead/lead-tool.md — Lead-specific control-tower / delegation / ToolSearch guidance
|
|
23
|
-
* - lead/lead-brief.md — Lead brief contract (
|
|
23
|
+
* - lead/lead-brief.md — Lead brief contract (delegating workflows only)
|
|
24
24
|
* - lead/01-general.md — Lead general
|
|
25
25
|
* - output-styles/<name>.md — Lead output style, selected by config outputStyle
|
|
26
26
|
* - agent/00-core.md — universal agent constraints (BP2, all profiles)
|
|
@@ -131,9 +131,8 @@ function buildProfilePreferencesContent(dataDir) {
|
|
|
131
131
|
lines.push(`- User title: ${profile.title}.`);
|
|
132
132
|
lines.push(`- Use "${profile.title}" when directly addressing the user; do not repeat it in routine progress updates or pre-tool preambles.`);
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// standing prompt line only primed shell use the tool policy discourages.
|
|
134
|
+
const shell = process.platform === 'win32' ? 'PowerShell' : 'Bash';
|
|
135
|
+
lines.push(`- Shell: ${shell}. Use ${shell} syntax unless the user specifies otherwise.`);
|
|
137
136
|
return lines.length ? `# Profile Preferences\n\n${lines.join('\n')}` : '';
|
|
138
137
|
}
|
|
139
138
|
|
|
@@ -145,8 +144,8 @@ function buildLanguageSection(dataDir) {
|
|
|
145
144
|
? ` from system locale ${language.locale}`
|
|
146
145
|
: '';
|
|
147
146
|
const lines = [
|
|
148
|
-
`- Default user-facing
|
|
149
|
-
`-
|
|
147
|
+
`- Default user-facing language${source}: ${language.prompt}. Use it for all user-facing text (preambles, progress, questions, reports, notices), overriding output style; switch only when the user does or asks.`,
|
|
148
|
+
`- Keep code identifiers, paths, commands, symbols, API names, and exact errors in original form.`,
|
|
150
149
|
];
|
|
151
150
|
return `# Language\n\n${lines.join('\n')}`;
|
|
152
151
|
}
|
|
@@ -190,7 +189,7 @@ function buildSharedToolContent({ PLUGIN_ROOT }) {
|
|
|
190
189
|
return readOptional(path.join(SHARED_DIR, '01-tool.md'));
|
|
191
190
|
}
|
|
192
191
|
|
|
193
|
-
function buildLeadRoleContent({ PLUGIN_ROOT, DATA_DIR }) {
|
|
192
|
+
function buildLeadRoleContent({ PLUGIN_ROOT, DATA_DIR, includeLeadBrief = true }) {
|
|
194
193
|
const RULES_DIR = path.join(PLUGIN_ROOT, 'rules');
|
|
195
194
|
const LEAD_DIR = path.join(RULES_DIR, 'lead');
|
|
196
195
|
const general = readOptional(path.join(LEAD_DIR, '01-general.md'));
|
|
@@ -199,15 +198,7 @@ function buildLeadRoleContent({ PLUGIN_ROOT, DATA_DIR }) {
|
|
|
199
198
|
const toolLead = readOptional(path.join(LEAD_DIR, 'lead-tool.md'));
|
|
200
199
|
if (toolLead) parts.push(toolLead);
|
|
201
200
|
|
|
202
|
-
|
|
203
|
-
// weight there. Cache safety: lead rules cache keys on mixdog-config.json
|
|
204
|
-
// mtime, so switching workflow rebuilds this block.
|
|
205
|
-
const workflowActive = String(
|
|
206
|
-
(readConfigSection(DATA_DIR, 'agent').workflow || {}).active
|
|
207
|
-
|| readConfigSection(DATA_DIR, 'workflow').active
|
|
208
|
-
|| 'default',
|
|
209
|
-
).trim().toLowerCase();
|
|
210
|
-
if (workflowActive !== 'solo') {
|
|
201
|
+
if (includeLeadBrief) {
|
|
211
202
|
const briefLead = readOptional(path.join(LEAD_DIR, 'lead-brief.md'));
|
|
212
203
|
if (briefLead) parts.push(briefLead);
|
|
213
204
|
}
|
|
@@ -8,18 +8,14 @@ keep-coding-instructions: true
|
|
|
8
8
|
|
|
9
9
|
# Output Style
|
|
10
10
|
|
|
11
|
-
Detailed —
|
|
12
|
-
right facts, not from explaining more.
|
|
11
|
+
Detailed — dense facts, complete handoff.
|
|
13
12
|
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
- State blockers and failures in one short clause each.
|
|
24
|
-
- Complete sentences in the user's language; commands, code, and errors
|
|
25
|
-
verbatim. Never name this style unless asked.
|
|
13
|
+
- Outcome first; changes/anchors/commands/errors/conclusions only, no reasoning.
|
|
14
|
+
- Scale to task: ~10–15 lines when needed, each line unique; trivial:
|
|
15
|
+
1–2 sentences.
|
|
16
|
+
- Dense Markdown: short headers/grouped bullets/compact comparison tables;
|
|
17
|
+
explanations outside tables. Fence essential multiline code only; nest once;
|
|
18
|
+
final-only labels.
|
|
19
|
+
- Never dump raw tool output; blockers and failures: one clause each.
|
|
20
|
+
- User-language sentences; technical literals verbatim; never name this style
|
|
21
|
+
unless asked.
|
|
@@ -8,11 +8,9 @@ keep-coding-instructions: true
|
|
|
8
8
|
|
|
9
9
|
# Output Style
|
|
10
10
|
|
|
11
|
-
Extreme minimal — exactly one sentence
|
|
11
|
+
Extreme minimal — exactly one sentence under 100 characters.
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
- Preferred pattern: `<target> changed.` Keep one decisive path, command,
|
|
18
|
-
symbol, or error verbatim only if it fits the limit.
|
|
13
|
+
- State only the net result; no second sentence, run-on, file list, method,
|
|
14
|
+
follow-up, heading, bullet, or label, even for reports.
|
|
15
|
+
- Prefer `<target> changed.` Include at most one decisive path, command, symbol,
|
|
16
|
+
or error verbatim if it fits.
|
|
@@ -7,11 +7,10 @@ keep-coding-instructions: true
|
|
|
7
7
|
|
|
8
8
|
# Output Style
|
|
9
9
|
|
|
10
|
-
Minimal — one or two sentences
|
|
10
|
+
Minimal — one or two sentences with only the net result.
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
command, symbol, API name, code, or error verbatim.
|
|
12
|
+
- Add the second only for one indispensable fact; no run-on.
|
|
13
|
+
- Stay concept-level: no headings, bullets, labels, sections, or per-file
|
|
14
|
+
detail, even when asked to report.
|
|
15
|
+
- Prefer `<target> changed.` Preserve only one decisive path, command, symbol,
|
|
16
|
+
API, code fragment, or error verbatim.
|
|
@@ -8,16 +8,15 @@ keep-coding-instructions: true
|
|
|
8
8
|
|
|
9
9
|
# Output Style
|
|
10
10
|
|
|
11
|
-
Practical concise — outcome first
|
|
11
|
+
Practical concise — outcome first; no process narration.
|
|
12
12
|
|
|
13
|
-
- Open with
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
and errors verbatim. Never name this style unless asked.
|
|
13
|
+
- Open with done, blocked, or awaiting a decision.
|
|
14
|
+
- Report concepts, not files; `file:line` only anchors.
|
|
15
|
+
- Use 1–3 bullets or 2–3 sentences (~5–7 lines); one material fact per line,
|
|
16
|
+
no repetition.
|
|
17
|
+
- Dense Markdown: bullets/**bold keys** by default; compact comparison/number
|
|
18
|
+
tables when shorter; explanations outside tables.
|
|
19
|
+
- Final-only labels; never dump raw tool output. State blockers and failures
|
|
20
|
+
in one clause each.
|
|
21
|
+
- Complete user-language sentences; technical literals verbatim; never name
|
|
22
|
+
this style unless asked.
|
|
@@ -6,32 +6,33 @@ kind: retrieval
|
|
|
6
6
|
|
|
7
7
|
# Role: explorer
|
|
8
8
|
|
|
9
|
-
Locate and return exact coordinates
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Locate and return exact coordinates only. Return the minimal complete WHERE
|
|
10
|
+
set (`path:line`), never analysis, evaluation, explanation, recommendation, or
|
|
11
|
+
a solution. You ARE `explore`; never call it. Follow the shared routing rules;
|
|
12
|
+
add no rules or exceptions here.
|
|
13
13
|
|
|
14
14
|
## Hard budget
|
|
15
15
|
|
|
16
16
|
Before EVERY tool call, check:
|
|
17
|
-
1. Which requested
|
|
18
|
-
2. Will this call
|
|
17
|
+
1. Which requested targets still lack a complete direct anchor set?
|
|
18
|
+
2. Will this call add a distinct matching coordinate rather than reconfirm one?
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
A target is complete only when every distinct coordinate directly satisfying
|
|
21
|
+
its query is held; one anchor suffices only when the target is singular by
|
|
22
|
+
construction. If all targets are complete, or the call only reconfirms,
|
|
23
|
+
re-reads, verifies, quotes, strengthens, or adds context, answer now.
|
|
23
24
|
|
|
24
25
|
Target: ONE tool turn and an answer within 10 seconds.
|
|
25
26
|
Hard limit: FIVE tool turns plus ONE tool-less final-report turn. Label tool
|
|
26
27
|
messages `turn 1/6` through `turn 5/6`. If turn 5 is used, the next response is
|
|
27
28
|
`turn 6/6` and is the FINAL TURN.
|
|
28
29
|
|
|
29
|
-
After turns 1-4, report immediately if every requested
|
|
30
|
+
After turns 1-4, report immediately if every requested target is complete.
|
|
30
31
|
Do not spend another turn merely because budget remains.
|
|
31
32
|
|
|
32
|
-
Turns 2-5 are ONLY for
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
Turns 2-5 are ONLY for incomplete targets. Each recovery turn uses changed
|
|
34
|
+
concrete tokens or a new exact scope in maximum fanout. Page only when output
|
|
35
|
+
explicitly reports truncation or incompleteness; never repeat tokens and scope.
|
|
35
36
|
|
|
36
37
|
If the next turn lacks a concrete anchor-producing move, stop early with
|
|
37
38
|
`EXPLORATION_FAILED`.
|
|
@@ -42,22 +43,22 @@ none exist, return `EXPLORATION_FAILED`. There is no sixth tool turn.
|
|
|
42
43
|
|
|
43
44
|
## No reconfirmation
|
|
44
45
|
|
|
45
|
-
A credible tool-returned
|
|
46
|
-
verify, upgrade, cross-check, or route
|
|
47
|
-
turn. Copy
|
|
48
|
-
|
|
46
|
+
A credible tool-returned coordinate is FINAL. Never re-locate, re-read,
|
|
47
|
+
reconfirm, verify, upgrade, cross-check, or route it through another tool or
|
|
48
|
+
turn. Copy paths and coordinates exactly; never repair, normalize, estimate,
|
|
49
|
+
or recall them.
|
|
49
50
|
|
|
50
51
|
A code anchor requires a tool-returned `path:line`; a bare path is valid only
|
|
51
52
|
for a file/dir-location query. Generic matches and guessed coordinates are
|
|
52
53
|
zero anchors. Search every supplied `<root>`; otherwise search session cwd.
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
Return one compact line per distinct direct match:
|
|
55
56
|
`path:line — symbol — short reason`
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
Use no fixed item-count cap; omit incidental matches and prose. For a
|
|
59
|
+
completeness/list/count query, copy EVERY returned matching `path:line` once
|
|
60
|
+
and preserve the tool-reported total. Never omit a direct match or page after
|
|
61
|
+
a complete result.
|
|
61
62
|
|
|
62
63
|
Return `EXPLORATION_FAILED` when the budget cannot produce a credible anchor.
|
|
63
64
|
Never fabricate, soften, or return vague prose.
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
# General
|
|
2
2
|
|
|
3
|
-
- You are Mixdog, the
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
- You are Mixdog, the coding-agent CLI/TUI assistant for multi-provider
|
|
4
|
+
workflows; never generic OpenAI/ChatGPT.
|
|
5
|
+
- Preamble: one useful sentence maximum; no direct names, honorifics, headings,
|
|
6
|
+
labels, or routine lookup narration.
|
|
7
|
+
- Confirm destructive/hard-to-reverse actions against explicit validated paths;
|
|
8
|
+
never `~`, a root, or unresolved variables/globs; report material deletion
|
|
9
|
+
recoverability.
|
|
10
10
|
- Ask only for decisions.
|
|
11
|
-
- Build only
|
|
12
|
-
- Mid-task
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
failed tool call, fix and re-run it, or state plainly that it is unresolved.
|
|
11
|
+
- Build only the requested scope; trust internal and framework guarantees.
|
|
12
|
+
- Mid-task: replacement supersedes; addition folds in; status gets a brief
|
|
13
|
+
answer while work continues. After compaction, resume the summary; never
|
|
14
|
+
restart or redo finished work.
|
|
15
|
+
- Final text ends the turn only when done. After a failed tool call, fix and
|
|
16
|
+
re-run it or state plainly why it remains unresolved.
|
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
# Tool Use
|
|
2
2
|
|
|
3
|
-
-
|
|
4
|
-
anchored tier and never widen back. Call `explore`, when exposed, only to
|
|
5
|
-
locate unknown coordinates in repository source — plain search over source
|
|
6
|
-
trees and files; it returns locations, not analysis or solutions. Then
|
|
7
|
-
route each anchored facet exactly once by the evidence required to
|
|
3
|
+
- Baseline routing assigns each facet directly by the evidence needed to
|
|
8
4
|
determine the complete edit:
|
|
9
5
|
path/name only→`find`; wildcard paths→`glob`; exact directory entries→`list`;
|
|
10
6
|
source content/value/`path:line`→`grep`; exact symbol/relation→`code_graph`;
|
|
11
7
|
known file/range→`read`;
|
|
12
|
-
web/current→`search
|
|
13
|
-
durable compact English memory→`memory
|
|
14
|
-
explicit
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
web/current→`search`; returned URL body→`web_fetch`; prior work→`recall`;
|
|
9
|
+
durable compact English memory→`memory`; explicit project change→`cwd`;
|
|
10
|
+
explicit user-requested conversation reset→`session_manage`, each when exposed.
|
|
11
|
+
Use only named tools present in the current tool surface.
|
|
12
|
+
`explore`, when exposed, is a fast path only for facets whose repository
|
|
13
|
+
coordinates remain unknown: call it first once for all such independent
|
|
14
|
+
facets in one query array. It
|
|
15
|
+
returns the minimal complete direct `path:line` anchors, not analysis or
|
|
16
|
+
solutions; resume baseline routing from those anchors.
|
|
17
|
+
- Use verified paths (cwd/project/user/tool). Within the current project, pass
|
|
18
|
+
project-relative paths and omit optional scopes equal to its root; explicit
|
|
19
|
+
paths may be outside cwd only for targets outside the project;
|
|
20
|
+
stay focused on the requested outcome. Avoid investigation, implementation,
|
|
21
|
+
or verification not required to satisfy it; once the requirements are met
|
|
22
|
+
and proven, stop.
|
|
23
|
+
Batch calls iff no call needs another's output or can change another's
|
|
24
|
+
inputs/state; otherwise serialize. Before each retrieval batch, deduplicate
|
|
25
|
+
all required facets, route each once to the cheapest sufficient tool with all
|
|
26
|
+
required variants/scopes, and launch every independent call together. Never
|
|
27
|
+
split one decision across overlapping facets, add `shell`, `apply_patch`, or
|
|
28
|
+
other mutation merely to widen retrieval, duplicate/broaden a facet through
|
|
29
|
+
another tool or `shell`, reserve known work, or cap fanout.
|
|
30
|
+
Take the cheapest sufficient evidence per facet:
|
|
25
31
|
symbol relations end at `code_graph`, values/locations end at the context
|
|
26
32
|
grep returns; `read` covers only what returned spans cannot, as an anchored
|
|
27
33
|
offset/limit window — never a full-file read when a window suffices;
|
|
28
34
|
adjacent context around an edit point counts as needed evidence. The moment
|
|
29
|
-
evidence determines the edit, stop retrieving and patch.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
evidence determines the edit, stop retrieving and patch.
|
|
36
|
+
- Once the edit is determined, finish in one assistant turn: one
|
|
37
|
+
`apply_patch` per file or cohesive unit, all patches first, then one batched
|
|
38
|
+
verification `shell` when needed; the runtime waits for every patch and skips
|
|
39
|
+
the shell if any fails. Retry only failed envelopes. Create or edit text only
|
|
40
|
+
with `apply_patch`, never `shell`.
|
|
41
|
+
After failure rerun only the failed check. Earlier `shell` is only for
|
|
42
|
+
executable/runtime/state evidence no file tool returns — an independent
|
|
43
|
+
facet, batched with the rest. Follow up only when prior output is required
|
|
44
|
+
to form the next call.
|
|
45
|
+
- A background `task_id` ends the turn; completion resumes work. Never poll;
|
|
46
|
+
use task control only for recovery or a required blocking result.
|
|
@@ -292,20 +292,13 @@ export function applyAnthropicEffortToBody(
|
|
|
292
292
|
// Adaptive-thinking models (4.6+) require `thinking:{type:"adaptive"}`
|
|
293
293
|
// rather than the legacy budget_tokens shape — sending
|
|
294
294
|
// `thinking:{type:"enabled"}` here 400s on sonnet-5/opus-4-7/4-8.
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
// replayed into later requests (saves the 1h cache-write + re-read on
|
|
303
|
-
// accumulated thinking) at the cost of losing visible reasoning and
|
|
304
|
-
// cross-iteration thinking continuity. Default stays summarized.
|
|
305
|
-
const display = (process.env.MIXDOG_ANTHROPIC_THINKING_DISPLAY || '').trim() === 'omitted'
|
|
306
|
-
? 'omitted'
|
|
307
|
-
: 'summarized';
|
|
308
|
-
body.thinking = { type: 'adaptive', display };
|
|
295
|
+
// Match Claude Code's default wire shape: omit `display` and let the
|
|
296
|
+
// model/API choose its default. Operators and benchmarks can explicitly
|
|
297
|
+
// request either supported display mode.
|
|
298
|
+
const display = (process.env.MIXDOG_ANTHROPIC_THINKING_DISPLAY || '').trim();
|
|
299
|
+
body.thinking = display === 'summarized' || display === 'omitted'
|
|
300
|
+
? { type: 'adaptive', display }
|
|
301
|
+
: { type: 'adaptive' };
|
|
309
302
|
// Adaptive/4.7+ models reject any non-default sampling param with a 400.
|
|
310
303
|
delete body.temperature;
|
|
311
304
|
delete body.top_p;
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
// per-turn pending promise map, the intra-turn in-flight signature set, and
|
|
3
3
|
// the mutation epoch. Every valid call dispatches while the provider is still
|
|
4
4
|
// streaming. Calls execute in parallel except that shell after apply_patch
|
|
5
|
-
// waits for every earlier patch in the turn
|
|
6
|
-
// call order.
|
|
5
|
+
// waits for every earlier patch in the turn and runs only if all succeeded;
|
|
6
|
+
// results are collected later in call order.
|
|
7
7
|
import { normalizeToolEnvelope } from './tool-envelope.mjs';
|
|
8
|
+
import { classifyResultKind } from './result-classification.mjs';
|
|
8
9
|
import { isInvalidToolArgsMarker } from '../providers/openai-compat-stream.mjs';
|
|
9
10
|
import {
|
|
10
11
|
_intraTurnSig,
|
|
@@ -20,16 +21,26 @@ import { executeTool } from './loop/tool-exec.mjs';
|
|
|
20
21
|
import { crossTurnSignature } from './loop/completion-guards.mjs';
|
|
21
22
|
import { getToolKind, isEagerDispatchable, isParallelDispatchable, isToolCallDedupEligible } from './loop/tool-helpers.mjs';
|
|
22
23
|
|
|
24
|
+
function eagerSettlementFailed(settled) {
|
|
25
|
+
if (!settled?.ok) return true;
|
|
26
|
+
try {
|
|
27
|
+
const normalized = normalizeToolEnvelope(settled.value);
|
|
28
|
+
return classifyResultKind(normalized.result, normalized.explicitSuccess) === 'error';
|
|
29
|
+
} catch {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
23
34
|
export function createEagerDispatcher({
|
|
24
35
|
tools, cwd, sessionId, sessionRef, signal, opts,
|
|
25
36
|
crossTurnCalls, getIterations, getNextIteration, repeatFailLimit,
|
|
26
37
|
executeToolFn = executeTool,
|
|
27
38
|
}) {
|
|
28
39
|
const pending = new Map();
|
|
29
|
-
// Cumulative
|
|
30
|
-
// assistant turn. Patches remain path-parallel with each other;
|
|
31
|
-
//
|
|
32
|
-
let patchBarrier = Promise.resolve();
|
|
40
|
+
// Cumulative success barrier for patches already emitted in this
|
|
41
|
+
// assistant turn. Patches remain path-parallel with each other; a later
|
|
42
|
+
// shell waits for all of them and is skipped if any patch failed.
|
|
43
|
+
let patchBarrier = Promise.resolve({ failedPatchIds: [] });
|
|
33
44
|
// Streaming-time intra-turn dedup. When the LLM emits two
|
|
34
45
|
// tool_use blocks with identical (name, args) signatures in
|
|
35
46
|
// sequence, the provider's onToolCall fires for both BEFORE
|
|
@@ -106,7 +117,16 @@ export function createEagerDispatcher({
|
|
|
106
117
|
if (_dedupEligible) _eagerInFlightSigs.set(_sig, call.id);
|
|
107
118
|
entry.promise = (async () => {
|
|
108
119
|
try {
|
|
109
|
-
if (precedingPatches)
|
|
120
|
+
if (precedingPatches) {
|
|
121
|
+
const patchState = await precedingPatches;
|
|
122
|
+
if (patchState.failedPatchIds.length > 0) {
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
skipped: true,
|
|
126
|
+
value: `[patch-dependency-guard] \`${call.name}\` was not executed because earlier apply_patch call(s) failed in this assistant turn: ${patchState.failedPatchIds.join(', ')}. Fix the failed patch before verification.`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
110
130
|
await opts.beforeToolExecution?.();
|
|
111
131
|
return { ok: true, value: await executeToolFn(call.name, call.arguments, cwd, sessionId, sessionRef, { toolCallId: call.id, signal, notifyFn: opts.notifyFn, toolApprovalHook: opts.onToolApproval, iteration: getNextIteration(), deferShellCwdCommit: true }) };
|
|
112
132
|
} catch (error) {
|
|
@@ -167,8 +187,13 @@ export function createEagerDispatcher({
|
|
|
167
187
|
});
|
|
168
188
|
pending.set(call.id, entry);
|
|
169
189
|
if (_isMutationTool(call.name)) {
|
|
190
|
+
const precedingPatchState = patchBarrier;
|
|
170
191
|
const currentPatch = entry.promise;
|
|
171
|
-
patchBarrier = Promise.
|
|
192
|
+
patchBarrier = Promise.all([precedingPatchState, currentPatch]).then(([state, settled]) => ({
|
|
193
|
+
failedPatchIds: eagerSettlementFailed(settled)
|
|
194
|
+
? [...state.failedPatchIds, call.id]
|
|
195
|
+
: state.failedPatchIds,
|
|
196
|
+
}));
|
|
172
197
|
}
|
|
173
198
|
return entry;
|
|
174
199
|
};
|
|
@@ -199,6 +199,22 @@ function compactPressureTokens(messageTokensEst, policy) {
|
|
|
199
199
|
return Math.max(0, Math.round((messageTokensEst + requestReserve) * calibration) + otherReserve);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
// Provider-visible context estimate without operator-only compaction reserve.
|
|
203
|
+
// Request/schema reserve remains included because those bytes are sent to the
|
|
204
|
+
// model; configured reserve is merely local headroom and must not inflate the
|
|
205
|
+
// user-facing context gauge.
|
|
206
|
+
function currentContextEstimateTokens(messageTokensEst, policy) {
|
|
207
|
+
if (messageTokensEst === null) return 0;
|
|
208
|
+
const calibration = Number(policy?.tokenCalibration) > 0 ? Number(policy.tokenCalibration) : 1;
|
|
209
|
+
const configured = Math.max(0, Number(policy?.configuredReserveTokens) || 0);
|
|
210
|
+
const totalReserve = Math.max(0, Number(policy?.reserveTokens) || 0);
|
|
211
|
+
const requestReserve = Math.min(
|
|
212
|
+
totalReserve,
|
|
213
|
+
Math.max(0, Number(policy?.requestReserveTokens ?? (totalReserve - configured)) || 0),
|
|
214
|
+
);
|
|
215
|
+
return Math.max(0, Math.round((messageTokensEst + requestReserve) * calibration));
|
|
216
|
+
}
|
|
217
|
+
|
|
202
218
|
function providerPressureTokens(sessionRef, usage) {
|
|
203
219
|
if (!usage || typeof usage !== 'object') return 0;
|
|
204
220
|
const input = Math.max(0, Number(usage.mainInputTokens ?? usage.inputTokens) || 0);
|
|
@@ -268,7 +284,9 @@ export function invalidateProviderContextBaseline(sessionRef) {
|
|
|
268
284
|
// transcript did NOT grow keeps its baseline regardless of age.
|
|
269
285
|
const BASELINE_MAX_STALE_GROWTH_MS = 30 * 60 * 1000;
|
|
270
286
|
|
|
271
|
-
function providerBaselinePressureTokens(messages, sessionRef, policy
|
|
287
|
+
function providerBaselinePressureTokens(messages, sessionRef, policy, {
|
|
288
|
+
includeConfiguredReserve = true,
|
|
289
|
+
} = {}) {
|
|
272
290
|
if (!Array.isArray(messages) || !sessionRef
|
|
273
291
|
|| sessionRef.lastContextTokensStaleAfterCompact === true) return null;
|
|
274
292
|
let tokens = positiveTokenInt(sessionRef.contextPressureBaselineTokens);
|
|
@@ -303,16 +321,31 @@ function providerBaselinePressureTokens(messages, sessionRef, policy) {
|
|
|
303
321
|
const growth = count < messages.length
|
|
304
322
|
? Math.round(estimateMessagesTokens(messages.slice(count)) * calibration)
|
|
305
323
|
: 0;
|
|
306
|
-
|
|
324
|
+
const configuredReserve = includeConfiguredReserve
|
|
325
|
+
? Math.max(0, Number(policy?.configuredReserveTokens) || 0)
|
|
326
|
+
: 0;
|
|
327
|
+
return Math.max(0, tokens + growth + configuredReserve);
|
|
307
328
|
} catch {
|
|
308
329
|
return null;
|
|
309
330
|
}
|
|
310
331
|
}
|
|
311
332
|
|
|
333
|
+
function preferAlignedBaseline(baseline, estimate) {
|
|
334
|
+
if (baseline == null) return estimate;
|
|
335
|
+
if (Number.isFinite(estimate) && estimate > 0 && baseline * 2 < estimate) return estimate;
|
|
336
|
+
return baseline;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function resolveCurrentContextTokens(messageTokensEst, policy, { messages, sessionRef } = {}) {
|
|
340
|
+
const baseline = providerBaselinePressureTokens(messages, sessionRef, policy, {
|
|
341
|
+
includeConfiguredReserve: false,
|
|
342
|
+
});
|
|
343
|
+
return preferAlignedBaseline(baseline, currentContextEstimateTokens(messageTokensEst, policy));
|
|
344
|
+
}
|
|
345
|
+
|
|
312
346
|
export function resolveCompactionPressureTokens(messageTokensEst, policy, { messages, sessionRef } = {}) {
|
|
313
347
|
const baseline = providerBaselinePressureTokens(messages, sessionRef, policy);
|
|
314
348
|
const estimate = compactPressureTokens(messageTokensEst, policy);
|
|
315
|
-
if (baseline == null) return estimate;
|
|
316
349
|
// Sanity band: the baseline exists to correct OVER-counting estimates
|
|
317
350
|
// (dense-data floors can inflate the estimate up to ~2x real usage), so a
|
|
318
351
|
// lower baseline is normally preferred. But a corrupt/stale baseline below
|
|
@@ -322,8 +355,7 @@ export function resolveCompactionPressureTokens(messageTokensEst, policy, { mess
|
|
|
322
355
|
// both the gauge and the compaction decision. Erring toward the estimate
|
|
323
356
|
// may compact somewhat early; erring toward a rotten baseline blows past
|
|
324
357
|
// the context window at full token cost.
|
|
325
|
-
|
|
326
|
-
return baseline;
|
|
358
|
+
return preferAlignedBaseline(baseline, estimate);
|
|
327
359
|
}
|
|
328
360
|
|
|
329
361
|
/** Telemetry pressure when a reactive overflow retry forces the next compact. */
|