mixdog 0.9.109 → 0.9.111
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 +1 -2
- package/scripts/routing-corpus.mjs +5 -6
- package/scripts/run-suite.mjs +2 -1
- package/src/app.mjs +0 -1
- package/src/defaults/agents.json +0 -12
- package/src/defaults/skills/setup/SKILL.md +1 -1
- package/src/headless-command.mjs +1 -3
- package/src/headless-role.mjs +2 -4
- package/src/help.mjs +1 -1
- package/src/rules/shared/01-tool.md +33 -37
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +6 -6
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +2 -25
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +3 -3
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -1
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +1 -1
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +7 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +0 -1
- package/src/runtime/agent/orchestrator/config.mjs +6 -6
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -2
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +31 -18
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +98 -12
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +64 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +18 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +25 -16
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +7 -25
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +0 -12
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -29
- package/src/runtime/agent/orchestrator/stall-policy.mjs +2 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +13 -6
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +4 -6
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +11 -2
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +2 -15
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +22 -35
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +37 -14
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +33 -61
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +65 -4
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +6 -37
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -5
- package/src/runtime/channels/lib/output-forwarder.mjs +0 -13
- package/src/runtime/channels/lib/tool-format.mjs +1 -2
- package/src/runtime/search/index.mjs +12 -6
- package/src/runtime/search/tool-defs.mjs +2 -2
- package/src/runtime/shared/agent-route-config.mjs +2 -3
- package/src/runtime/shared/child-spawn-gate.mjs +1 -1
- package/src/runtime/shared/pristine-execution-contract.json +4 -1
- package/src/runtime/shared/resource-admission.mjs +1 -1
- package/src/runtime/shared/tool-card-model.mjs +3 -5
- package/src/runtime/shared/tool-primitives.mjs +0 -1
- package/src/runtime/shared/tool-result-summary.mjs +0 -7
- package/src/runtime/shared/tool-surface.mjs +1 -14
- package/src/session-runtime/runtime-core.mjs +1 -24
- package/src/session-runtime/session-title.mjs +14 -1
- package/src/session-runtime/settings-api.mjs +0 -8
- package/src/session-runtime/tool-catalog-data.mjs +4 -7
- package/src/session-runtime/tool-catalog-schema.mjs +1 -1
- package/src/session-runtime/workflow-agents-api.mjs +0 -3
- package/src/session-runtime/workflow.mjs +3 -7
- package/src/standalone/agent-tool/helpers.mjs +0 -1
- package/src/standalone/agent-tool/render.mjs +1 -1
- package/src/standalone/agent-tool/shard-spread.mjs +2 -2
- package/src/standalone/agent-tool/spawn-flow.mjs +18 -0
- package/src/standalone/session-client.mjs +79 -20
- package/src/standalone/session-protocol.mjs +0 -1
- package/src/standalone/session-transport.mjs +19 -3
- package/src/tui/app/model-options.mjs +2 -3
- package/src/tui/app/onboarding-steps.mjs +1 -1
- package/src/tui/app/settings-picker.mjs +0 -12
- package/src/tui/app/transcript-row-estimate.mjs +1 -1
- package/src/tui/app/use-transcript-activity.mjs +7 -17
- package/src/tui/dist/index.mjs +9 -51
- package/src/tui/session/agent-envelope.mjs +1 -1
- package/src/tui/session/live-share.mjs +1 -1
- package/src/tui/session/session-api.mjs +0 -10
- package/src/tui/session/turn.mjs +2 -2
- package/src/tui/session-local.mjs +8 -11
- package/src/ui/statusline-agents.mjs +1 -2
- package/src/ui/statusline-format.mjs +1 -1
- package/src/ui/statusline.mjs +1 -6
- package/src/workflows/default/WORKFLOW.md +2 -1
- package/src/agents/explore/AGENT.md +0 -8
- package/src/agents/explore/agent.json +0 -6
- package/src/rules/agent/30-explorer.md +0 -55
- package/src/standalone/explore-tool.mjs +0 -770
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mixdog",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.111",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone mixdog coding-agent CLI/TUI workspace.",
|
|
@@ -125,7 +125,6 @@
|
|
|
125
125
|
"bench:run": "node scripts/bench-run.mjs",
|
|
126
126
|
"bench:recall": "node scripts/recall-bench.mjs",
|
|
127
127
|
"bench:tui-load": "node scripts/tui-runtime-load-bench.mjs",
|
|
128
|
-
"bench:explore": "node scripts/explore-bench.mjs",
|
|
129
128
|
"bench:output-style": "node scripts/output-style-bench.mjs",
|
|
130
129
|
"bench:session-context": "node scripts/session-context-bench.mjs",
|
|
131
130
|
"bench:session-transport": "node scripts/session-transport-bench.mjs",
|
|
@@ -68,7 +68,6 @@ function argsSummary(tool, args) {
|
|
|
68
68
|
const values = args.symbols || args.files || args.symbol || args.file || '';
|
|
69
69
|
return clip(`${args.mode || '?'}:${Array.isArray(values) ? `[${values.length}]${values[0] || ''}` : values}`);
|
|
70
70
|
}
|
|
71
|
-
case 'explore': return arr(args.query);
|
|
72
71
|
case 'find': return clip(args.query);
|
|
73
72
|
case 'glob': return clip(Array.isArray(args.pattern) ? args.pattern[0] : args.pattern);
|
|
74
73
|
case 'list': return clip(basename(String(args.path || '')));
|
|
@@ -95,7 +94,7 @@ function targetValues(tool, args) {
|
|
|
95
94
|
? (args.files != null ? 'files' : 'file')
|
|
96
95
|
: symbolMode || args.mode === 'symbols' ? (args.symbols != null ? 'symbols' : 'symbol') : 'file';
|
|
97
96
|
} else if (tool === 'grep' || tool === 'glob') key = 'pattern';
|
|
98
|
-
else if (tool === 'find'
|
|
97
|
+
else if (tool === 'find') key = 'query';
|
|
99
98
|
const value = args[key];
|
|
100
99
|
return Array.isArray(value) ? value : value == null ? [] : [value];
|
|
101
100
|
}
|
|
@@ -110,7 +109,7 @@ function batchFields(tool, args) {
|
|
|
110
109
|
? (args?.files != null ? 'files' : args?.file != null ? 'file' : args?.symbols != null ? 'symbols' : 'symbol')
|
|
111
110
|
: null].filter(Boolean);
|
|
112
111
|
}
|
|
113
|
-
return [tool === 'read' || tool === 'list' ? 'path' : tool === 'find'
|
|
112
|
+
return [tool === 'read' || tool === 'list' ? 'path' : tool === 'find' ? 'query' : null].filter(Boolean);
|
|
114
113
|
}
|
|
115
114
|
function compatibleBatchCalls(tool, left, right) {
|
|
116
115
|
if (tool === 'read') {
|
|
@@ -149,7 +148,7 @@ function batchSpec(tool, args, forcedField = null) {
|
|
|
149
148
|
: (args.symbols != null ? 'symbols' : 'symbol');
|
|
150
149
|
return { field, values: targetValues(tool, args) };
|
|
151
150
|
}
|
|
152
|
-
const fieldName = forcedField || (tool === 'read' || tool === 'list' ? 'path' : tool === 'grep' || tool === 'glob' ? 'pattern' : tool === 'find'
|
|
151
|
+
const fieldName = forcedField || (tool === 'read' || tool === 'list' ? 'path' : tool === 'grep' || tool === 'glob' ? 'pattern' : tool === 'find' ? 'query' : null);
|
|
153
152
|
if (!fieldName) return null;
|
|
154
153
|
const value = args[fieldName];
|
|
155
154
|
return { field: fieldName, values: Array.isArray(value) ? value : value == null ? [] : [value] };
|
|
@@ -166,7 +165,7 @@ function sameIterationBatchObservations(sequence) {
|
|
|
166
165
|
if (isMutation(next.tool)) break;
|
|
167
166
|
group.push(next);
|
|
168
167
|
}
|
|
169
|
-
for (const candidate of ['read', 'grep', 'find', 'glob', 'list', '
|
|
168
|
+
for (const candidate of ['read', 'grep', 'find', 'glob', 'list', 'code_graph']) {
|
|
170
169
|
if (candidate === 'read') {
|
|
171
170
|
const calls = group.filter((entry) => entry.tool === 'read' && !entry.failed).map((entry) => ({ entry, targets: readTargets(entry.rawArgs) })).filter(({ targets }) => targets?.length);
|
|
172
171
|
if (calls.some(({ entry, targets }, index) => calls.some(({ entry: other, targets: otherTargets }, otherIndex) => (
|
|
@@ -238,7 +237,7 @@ function buildCase(sid, toolRows) {
|
|
|
238
237
|
const observations = [];
|
|
239
238
|
if (sequence.some((s) => s.tool === 'code_graph' && s.rawArgs?.mode === 'find_symbol' && !s.rawArgs?.file && !s.rawArgs?.files)) flags.push('find_symbol_noscope');
|
|
240
239
|
// Exact duplicate requests are the only relookup signal available in tool
|
|
241
|
-
// traces. Do not infer waste from counts, roles, turns, or
|
|
240
|
+
// traces. Do not infer waste from counts, roles, turns, or locator→inspection:
|
|
242
241
|
// exploration followed by inspection can be the intended route.
|
|
243
242
|
const seenRequests = new Set();
|
|
244
243
|
const readWindows = [];
|
package/scripts/run-suite.mjs
CHANGED
|
@@ -25,7 +25,6 @@ export const SUITES = {
|
|
|
25
25
|
'dead-owner-attach-test.mjs',
|
|
26
26
|
'debounced-skills-async-save-test.mjs',
|
|
27
27
|
'dispatch-persist-recovery-test.mjs',
|
|
28
|
-
'explore-prompt-policy-test.mjs',
|
|
29
28
|
'find-fuzzy-hidden-test.mjs',
|
|
30
29
|
'ingest-pure-conversation-smoke.mjs',
|
|
31
30
|
'internal-tools-normalization-test.mjs',
|
|
@@ -51,6 +50,7 @@ export const SUITES = {
|
|
|
51
50
|
'pretool-ask-runtime-test.mjs',
|
|
52
51
|
'prompt-input-parity-test.mjs',
|
|
53
52
|
'reactive-compact-persist-smoke.mjs',
|
|
53
|
+
'reasoning-replay-policy-test.mjs',
|
|
54
54
|
'repl-stream-finalize-test.mjs',
|
|
55
55
|
'result-classification-test.mjs',
|
|
56
56
|
'rg-runner-test.mjs',
|
|
@@ -60,6 +60,7 @@ export const SUITES = {
|
|
|
60
60
|
'session-title-controller-test.mjs',
|
|
61
61
|
'set-effort-config-test.mjs',
|
|
62
62
|
'shell-jobs-windows-hide-test.mjs',
|
|
63
|
+
'spawn-ws-prewarm-test.mjs',
|
|
63
64
|
'spinner-meta-test.mjs',
|
|
64
65
|
'statusline-agents-test.mjs',
|
|
65
66
|
'statusline-quota-hysteresis-test.mjs',
|
package/src/app.mjs
CHANGED
package/src/defaults/agents.json
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"agents": [
|
|
3
|
-
{
|
|
4
|
-
"agent": "explorer",
|
|
5
|
-
"slot": "explore",
|
|
6
|
-
"systemFile": "rules/agent/30-explorer.md",
|
|
7
|
-
"description": "Filesystem navigation agent invoked by the `explore` MCP tool",
|
|
8
|
-
"invokedBy": "explore",
|
|
9
|
-
"toolSchemaProfile": "read",
|
|
10
|
-
"schemaAllowedTools": ["grep", "find", "glob", "code_graph"],
|
|
11
|
-
"kind": "retrieval",
|
|
12
|
-
"permission": "read",
|
|
13
|
-
"stallCap": { "idleSeconds": 240, "toolRunningSeconds": 180 }
|
|
14
|
-
},
|
|
15
3
|
{
|
|
16
4
|
"agent": "cycle1-agent",
|
|
17
5
|
"slot": "cycle1",
|
|
@@ -73,7 +73,7 @@ apply it, and verify the result.
|
|
|
73
73
|
### Workflow / agent definitions
|
|
74
74
|
|
|
75
75
|
1. Workflows and agents are Markdown packs. Built-in services are Web Search,
|
|
76
|
-
|
|
76
|
+
and Maintainer. Mixdog ships editable starter agents `worker`,
|
|
77
77
|
`heavy-worker`, and `reviewer`; custom packs live at
|
|
78
78
|
`<mixdogData>/workflows/<id>/WORKFLOW.md` and
|
|
79
79
|
`<mixdogData>/agents/<id>/AGENT.md`.
|
package/src/headless-command.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const VALUE_OPTIONS = new Set(['--provider', '--model', '--effort', '--workflow']);
|
|
2
2
|
const FLAG_OPTIONS = new Set([
|
|
3
3
|
'--readonly', '--help', '-h', '--plain', '--react', '--remote', '--onboarding', '--fast',
|
|
4
|
-
'--
|
|
4
|
+
'--web-search', '--memory',
|
|
5
5
|
]);
|
|
6
6
|
const HEADLESS_ROLE_ALIASES = new Map([
|
|
7
|
-
['explorer', 'explore'], ['explore', 'explore'],
|
|
8
7
|
['maint', 'maintainer'], ['maintenance', 'maintainer'], ['maintainer', 'maintainer'],
|
|
9
8
|
['worker', 'worker'],
|
|
10
9
|
['heavy', 'heavy-worker'], ['heavyworker', 'heavy-worker'], ['heavy-worker', 'heavy-worker'],
|
|
@@ -108,7 +107,6 @@ export function classifyCliInvocation(argv = []) {
|
|
|
108
107
|
model: parsed.values['--model'],
|
|
109
108
|
effort: parsed.values['--effort'],
|
|
110
109
|
fast: argv.includes('--fast'),
|
|
111
|
-
explore: argv.includes('--explore'),
|
|
112
110
|
webSearch: argv.includes('--web-search'),
|
|
113
111
|
memory: argv.includes('--memory'),
|
|
114
112
|
toolMode: argv.includes('--readonly') ? 'readonly' : 'full',
|
package/src/headless-role.mjs
CHANGED
|
@@ -83,7 +83,6 @@ export async function runHeadlessRole({
|
|
|
83
83
|
model,
|
|
84
84
|
effort,
|
|
85
85
|
fast,
|
|
86
|
-
explore = false,
|
|
87
86
|
webSearch = false,
|
|
88
87
|
memory = false,
|
|
89
88
|
cwd = process.cwd(),
|
|
@@ -93,11 +92,10 @@ export async function runHeadlessRole({
|
|
|
93
92
|
} = {}) {
|
|
94
93
|
const cleanAgent = clean(agent);
|
|
95
94
|
const cleanMessage = clean(message);
|
|
96
|
-
// Classic headless surface:
|
|
97
|
-
// and opt back in per run (--
|
|
95
|
+
// Classic headless surface: web search and memory tools start OFF
|
|
96
|
+
// and opt back in per run (--web-search / --memory). An explicit
|
|
98
97
|
// MIXDOG_FEATURE_* value from the caller environment always wins.
|
|
99
98
|
for (const [key, enabled] of [
|
|
100
|
-
['MIXDOG_FEATURE_EXPLORE', explore],
|
|
101
99
|
['MIXDOG_FEATURE_WEB_SEARCH', webSearch],
|
|
102
100
|
['MIXDOG_FEATURE_MEMORY', memory],
|
|
103
101
|
]) {
|
package/src/help.mjs
CHANGED
|
@@ -21,7 +21,7 @@ export const HELP_LINES = [
|
|
|
21
21
|
'',
|
|
22
22
|
'Headless role commands require an explicit provider/model pair and run with',
|
|
23
23
|
'ephemeral config/data; host behavioral config and personal state are not loaded.',
|
|
24
|
-
'Roles:
|
|
24
|
+
'Roles: worker, heavy-worker, reviewer, maintainer, web-researcher.',
|
|
25
25
|
'',
|
|
26
26
|
'Slash commands (inside mixdog):',
|
|
27
27
|
' /clear start a fresh chat (alias: /new)',
|
|
@@ -2,51 +2,47 @@
|
|
|
2
2
|
|
|
3
3
|
- Baseline routing assigns each facet directly by the evidence needed to
|
|
4
4
|
determine the complete edit:
|
|
5
|
-
path/name only→`find`; wildcard/recursive paths→`glob
|
|
6
|
-
entries→`list`;
|
|
5
|
+
path/name only→`find`; wildcard/recursive paths→`glob` (including known-root
|
|
6
|
+
unknown descendants); exact directory entries→`list`;
|
|
7
7
|
source content/value/`path:line`→`grep`; exact symbol/relation→`code_graph`;
|
|
8
8
|
known file/range→`read`;
|
|
9
|
-
web/current→`search`; returned URL body→`web_fetch`; prior work→`recall
|
|
9
|
+
web/current→`search`; returned URL body→`web_fetch`; prior work→`recall`
|
|
10
|
+
(history only, never current local state);
|
|
10
11
|
durable compact English memory→`memory`; explicit project change→`cwd`;
|
|
11
12
|
explicit user-requested conversation reset→`session_manage`.
|
|
12
13
|
Use only named tools present in the current tool surface.
|
|
13
|
-
`explore`, when exposed, is a fast path only for facets whose repository
|
|
14
|
-
coordinates remain unknown: call it first once for all such independent
|
|
15
|
-
facets in one query array. It returns the minimal complete direct
|
|
16
|
-
`path:line` anchors, not analysis or solutions; resume baseline routing
|
|
17
|
-
from those anchors.
|
|
18
14
|
- Act only on verified identities (cwd/project/user/tool-returned) — paths,
|
|
19
15
|
module specifiers, symbols, data/record shapes alike; a guessed identity is
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
verified by one lookup or sample only when the next call or edit references
|
|
17
|
+
it. Within the current project, pass
|
|
22
18
|
project-relative paths and omit optional scopes equal to its root; explicit
|
|
23
19
|
paths may be outside cwd only for targets outside the project.
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
20
|
+
- Plan the fewest dependent rounds, then the fewest calls. A conclusive
|
|
21
|
+
result ends its facet, and known state — task/brief-supplied facts,
|
|
22
|
+
returned content, your own successful calls' effects — is never
|
|
23
|
+
re-acquired, broadened, or reconfirmed. Batch calls iff none needs
|
|
24
|
+
another's output or can change another's inputs/state; otherwise
|
|
25
|
+
serialize. Before each batch, deduplicate the facets still required by the request,
|
|
26
|
+
route each once to the cheapest sufficient tool with all required
|
|
27
|
+
variants/scopes, and launch every independent call together — never
|
|
28
|
+
split or duplicate a facet across tools, mutate merely to widen
|
|
29
|
+
retrieval, reserve known work, or cap fanout. Symbol relations end at
|
|
30
|
+
`code_graph`; values/locations end at the context grep returns; `read`
|
|
31
|
+
covers only what returned spans cannot, as an anchored offset/limit
|
|
32
|
+
window. The moment evidence determines the answer, edit, or deliverable,
|
|
33
|
+
stop retrieving; patch if needed.
|
|
34
|
+
- Once the edit or deliverable is determined, finish in one assistant turn:
|
|
35
|
+
issue `apply_patch` calls serially, never in parallel; use one cohesive call
|
|
36
|
+
with one file section per target, all patches first, then one
|
|
37
|
+
batched verification `shell` that runs the real required postconditions
|
|
38
|
+
on every changed file and produced artifact, never echoes a claim;
|
|
39
|
+
runtime waits for every patch and skips the shell
|
|
40
|
+
if any fails. Retry only failed envelopes; rerun a failed check only
|
|
41
|
+
after a fix that can change its result, else report it unresolved.
|
|
42
|
+
Hand-authored text is edited only with `apply_patch`; computed artifacts
|
|
43
|
+
(data/reports/derived values) come from `shell` computation, never
|
|
44
|
+
hand-transcribed numbers. Earlier `shell` is only for runtime/state
|
|
45
|
+
evidence unavailable to file tools—an independent facet, batched with
|
|
46
|
+
the rest.
|
|
51
47
|
- A background `task_id` ends the turn; completion resumes work. Never poll;
|
|
52
48
|
use task control only for recovery or a required blocking result.
|
|
@@ -47,7 +47,7 @@ import { resourceAdmission } from '../../../shared/resource-admission.mjs';
|
|
|
47
47
|
export { resolveMaintenanceRoute } from './maintenance-route.mjs';
|
|
48
48
|
|
|
49
49
|
// Cap agent role synthesis to ~3000 tokens (~12 KB at the 4 B/tok
|
|
50
|
-
// working average). Pool B
|
|
50
|
+
// working average). Pool B recall/search answers occasionally land
|
|
51
51
|
// 8-10k-token walls that then ride in the Lead context for the rest of the
|
|
52
52
|
// turn; the cap keeps those outliers bounded without touching the 95%+ of
|
|
53
53
|
// answers already under the threshold.
|
|
@@ -68,7 +68,7 @@ function formatCompactElapsedSeconds(ms) {
|
|
|
68
68
|
|
|
69
69
|
// True when an abort explicitly opted into partial salvage — the error object
|
|
70
70
|
// or the abort reason carries `salvagePartial: true`. A DEADLINE-driven caller
|
|
71
|
-
//
|
|
71
|
+
// A hard timeout sets it so partial output the sub-agent already produced
|
|
72
72
|
// are returned instead of discarded; user cancellation (ESC) never sets it and
|
|
73
73
|
// keeps the throw-everything behaviour.
|
|
74
74
|
function salvagePartialRequested(error, signal) {
|
|
@@ -151,7 +151,7 @@ export function resolveHiddenRoleSchemaAllowedTools(hidden) {
|
|
|
151
151
|
* against config.presets.
|
|
152
152
|
* - null — unresolved.
|
|
153
153
|
*
|
|
154
|
-
*
|
|
154
|
+
* Hidden maintenance roles mirror public spawning precedence:
|
|
155
155
|
* `agents.<role>` (including the `agents.maintenance` alias) → workflow route →
|
|
156
156
|
* maintenance route → Main. The cycle1/2/3 agents share the memory knob via
|
|
157
157
|
* their `maintKey: 'memory'` override. Scheduler and webhook are unchanged.
|
|
@@ -293,7 +293,7 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
293
293
|
agentId: agent,
|
|
294
294
|
});
|
|
295
295
|
|
|
296
|
-
// Callers
|
|
296
|
+
// Callers may pass an explicit
|
|
297
297
|
// `cwd` to scope the agent's filesystem view. Absolute path expected
|
|
298
298
|
// (aiWrapped already expands `~` and resolves relatives). When unset
|
|
299
299
|
// we pass `null` through instead of falling back to `process.cwd()`
|
|
@@ -418,7 +418,7 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
418
418
|
const _idleController = (agentWatchdogPolicyActive(_watchdogPolicy) && _linkSignal)
|
|
419
419
|
? new AbortController()
|
|
420
420
|
: null;
|
|
421
|
-
// Do not link factory parent, per-call
|
|
421
|
+
// Do not link factory parent, per-call cancellation, and the
|
|
422
422
|
// watchdog one at a time: each link replaces the previous listener in
|
|
423
423
|
// runtime-liveness. One composite survives askSession's controller
|
|
424
424
|
// swap and makes every source reach the provider call.
|
|
@@ -497,7 +497,7 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
497
497
|
});
|
|
498
498
|
process.stderr.write(`[agent-dispatch] agent=${agent} session=${session.id} elapsed=${Date.now() - _agentDispatchT0}ms\n`);
|
|
499
499
|
const raw = result?.content || '';
|
|
500
|
-
// Brief cap. Agent role answers (
|
|
500
|
+
// Brief cap. Agent role answers (recall/search)
|
|
501
501
|
// occasionally balloon to 8-10k token walls that then ride in the
|
|
502
502
|
// parent Lead's context for the rest of the turn. A 3000-token
|
|
503
503
|
// (~12 KB) ceiling trims the long tail while leaving the vast
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agent loop ceilings. Lead and
|
|
3
|
-
* runaway guard. Explorer is the sole bounded exception: locator work gets at
|
|
4
|
-
* at most five tool-capable turns, followed by the loop's tool-less report turn.
|
|
2
|
+
* Agent loop ceilings. Lead and delegated agents share one high runaway guard.
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
5
|
function envPositiveInt(name, fallback) {
|
|
@@ -15,29 +13,8 @@ function envPositiveInt(name, fallback) {
|
|
|
15
13
|
// to raise/lower the safety ceiling, never used as a general task-length budget.
|
|
16
14
|
export const LEAD_MAX_LOOP_ITERATIONS = envPositiveInt('MIXDOG_AGENT_MAX_LOOP', 200);
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
// bounded miss recovery. The override may shorten this but never add a sixth.
|
|
20
|
-
export const EXPLORE_MAX_LOOP_ITERATIONS = Math.min(
|
|
21
|
-
5,
|
|
22
|
-
envPositiveInt('MIXDOG_EXPLORE_MAX_LOOP', 5),
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Resolve the hard cap used by agentLoop for this session.
|
|
27
|
-
*
|
|
28
|
-
* Explorer: the lowest positive explicit/session value, clamped to its
|
|
29
|
-
* dedicated five-turn ceiling. Others: explicit → session-pinned → shared guard.
|
|
30
|
-
*/
|
|
16
|
+
/** Resolve the hard cap used by agentLoop for this session. */
|
|
31
17
|
export function resolveSessionMaxLoopIterations(sessionRef, explicit) {
|
|
32
|
-
const sessionAgent = String(sessionRef?.agent || '').trim().toLowerCase();
|
|
33
|
-
if (sessionAgent === 'explorer' || sessionAgent === 'explore') {
|
|
34
|
-
const requested = Number.isFinite(explicit) && explicit > 0
|
|
35
|
-
? Math.floor(explicit)
|
|
36
|
-
: Number.isFinite(sessionRef?.maxLoopIterations) && sessionRef.maxLoopIterations > 0
|
|
37
|
-
? Math.floor(sessionRef.maxLoopIterations)
|
|
38
|
-
: EXPLORE_MAX_LOOP_ITERATIONS;
|
|
39
|
-
return Math.min(EXPLORE_MAX_LOOP_ITERATIONS, requested);
|
|
40
|
-
}
|
|
41
18
|
if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);
|
|
42
19
|
if (Number.isFinite(sessionRef?.maxLoopIterations) && sessionRef.maxLoopIterations > 0) {
|
|
43
20
|
return Math.floor(sessionRef.maxLoopIterations);
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
// Ordering guarantee, stated in stall-policy.mjs: the provider layer — which
|
|
18
18
|
// can retry in place or fall back to non-streaming — must fire STRICTLY before
|
|
19
19
|
// the agent watchdog's terminal abort. Role abort budgets (worker/reviewer
|
|
20
|
-
// 300s
|
|
20
|
+
// 300s) sat at or BELOW the provider semantic-idle window
|
|
21
21
|
// (300s), inverting that order: the watchdog aborted the shared signal first,
|
|
22
22
|
// so the provider's recovery never ran and the `agent_stall` failure — which
|
|
23
23
|
// the classifier calls retryable — died on throwIfAborted instead. Hold the
|
|
@@ -140,7 +140,7 @@ export function watchdogPartialHandoffFromError(error, session, messageStartInde
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
// Salvage path for NON-watchdog aborts that explicitly opt in (the abort error
|
|
143
|
-
// / abort reason carries `salvagePartial: true` — e.g.
|
|
143
|
+
// / abort reason carries `salvagePartial: true` — e.g. a bounded wall-clock
|
|
144
144
|
// hard timeout). Same collection rule as the watchdog handoff: only assistant
|
|
145
145
|
// text appended during this run. Plain user cancellation never opts in, so ESC
|
|
146
146
|
// still discards the run.
|
|
@@ -266,7 +266,7 @@ export function resolveAgentWatchdogPolicy(agent, overrides = {}) {
|
|
|
266
266
|
? Math.min(DEFAULT_STALE_TIMEOUT_MS, backstopMs)
|
|
267
267
|
: DEFAULT_STALE_TIMEOUT_MS;
|
|
268
268
|
// Same floor for the public backstop: a workflow role (worker 300s,
|
|
269
|
-
//
|
|
269
|
+
// role-specific caps must not undercut the provider window either.
|
|
270
270
|
idleStaleMs = Math.max(idleStaleMs, PROVIDER_RECOVERY_FLOOR_MS);
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -29,7 +29,7 @@ export function resolveMaintenanceRoute({ preset, optsPreset, agent, config: cfg
|
|
|
29
29
|
try {
|
|
30
30
|
const config = cfgIn || loadConfig({ secrets: false });
|
|
31
31
|
const key = hidden.maintKey || hidden.slot;
|
|
32
|
-
const role = key === '
|
|
32
|
+
const role = key === 'memory' ? 'maintainer' : '';
|
|
33
33
|
if (!role) return config?.maintenance?.[key] ?? null;
|
|
34
34
|
const candidates = [
|
|
35
35
|
...configuredAgentRouteCandidates(config, role),
|
|
@@ -49,7 +49,7 @@ function normalizeAgentCompactionConfig(value = {}, { memoryEnabled = true } = {
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* @param {object} opts
|
|
52
|
-
* @param {string} opts.agent — canonical agent name ('worker', '
|
|
52
|
+
* @param {string} opts.agent — canonical agent name ('worker', 'reviewer', ...)
|
|
53
53
|
* @param {string} opts.presetName — resolved preset identifier
|
|
54
54
|
* @param {object} opts.preset — resolved preset object from agent-config
|
|
55
55
|
* @param {object} opts.runtimeSpec — resolveRuntimeSpec output; must carry .scopeKey / .lane
|
|
@@ -39,7 +39,13 @@ export function createTitleCompletion(deps = {}) {
|
|
|
39
39
|
config,
|
|
40
40
|
});
|
|
41
41
|
if (!route || typeof route !== 'object') {
|
|
42
|
-
|
|
42
|
+
const error = new Error('Session title maintenance route is unresolved.');
|
|
43
|
+
// Machine-readable marker: callers (session-title controller)
|
|
44
|
+
// downgrade this to a one-shot "titling disabled" skip instead of
|
|
45
|
+
// logging a stack per session (e.g. bench profiles without a
|
|
46
|
+
// maintainer/default route).
|
|
47
|
+
error.code = 'MAINTENANCE_ROUTE_UNRESOLVED';
|
|
48
|
+
throw error;
|
|
43
49
|
}
|
|
44
50
|
const providerName = String(route.provider || '').trim();
|
|
45
51
|
const model = String(route.model || '').trim();
|
|
@@ -137,7 +137,6 @@ const TOOL_ARG_KEYS = {
|
|
|
137
137
|
list: ['path', 'head_limit', 'offset'],
|
|
138
138
|
recall: ['query', 'limit', 'session_id', 'cwd'],
|
|
139
139
|
search: ['query', 'limit', 'cwd'],
|
|
140
|
-
explore: ['query', 'queries', 'limit', 'cwd'],
|
|
141
140
|
code_graph: ['mode', 'file', 'files', 'symbol', 'symbols', 'body', 'language', 'limit', 'depth', 'page', 'cwd'],
|
|
142
141
|
shell: ['command', 'cwd', 'timeout', 'mode', 'run_in_background', 'persistent', 'session_id'],
|
|
143
142
|
task: ['task_id', 'action', 'timeout_ms', 'poll_ms'],
|
|
@@ -22,13 +22,12 @@ export function getPluginData() {
|
|
|
22
22
|
// Canonical maintenance defaults. Single source of truth — imported by
|
|
23
23
|
// llm/index.mjs and setup-server.mjs so UI/runtime cannot drift from config.
|
|
24
24
|
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// maintenance aliases.
|
|
25
|
+
// Maintainer starts without a route so it dynamically inherits the Main route.
|
|
26
|
+
// Its explicit route lives canonically in `agents.maintainer`; load-time
|
|
27
|
+
// migration still accepts the older workflow / maintenance aliases.
|
|
29
28
|
// Webhook endpoints may omit a model and use the fallback route below.
|
|
30
29
|
// Legacy route slots accepted only at config ingress for migration.
|
|
31
|
-
const MAINTENANCE_SLOTS = Object.freeze(['
|
|
30
|
+
const MAINTENANCE_SLOTS = Object.freeze(['memory']);
|
|
32
31
|
|
|
33
32
|
// --- User profile (statusline /profile) -------------------------------------
|
|
34
33
|
// Supported response languages for the /profile picker. `system` is the default
|
|
@@ -340,7 +339,8 @@ function canonicalizeShellStorage(value) {
|
|
|
340
339
|
function canonicalizeModulesStorage(value) {
|
|
341
340
|
const modules = configObject(value);
|
|
342
341
|
delete modules.memory;
|
|
343
|
-
|
|
342
|
+
delete modules.explore;
|
|
343
|
+
for (const name of ['search']) {
|
|
344
344
|
if (!Object.prototype.hasOwnProperty.call(modules, name)) continue;
|
|
345
345
|
const raw = modules[name];
|
|
346
346
|
modules[name] = {
|
|
@@ -711,8 +711,7 @@ export function loadScopedRoleInstructions(agent, provider = null) {
|
|
|
711
711
|
agentRuleSectionsToEmit = hiddenPairs.map(p => `## ${p.name}\n\n${p.body}`);
|
|
712
712
|
agentSectionsToEmit = agentSections;
|
|
713
713
|
} else if (agent && classification.retrieval.has(agent)) {
|
|
714
|
-
// Retrieval agents
|
|
715
|
-
// (rules/agent/30-explorer.md) in BP2.
|
|
714
|
+
// Retrieval agents get their own contract section in BP2.
|
|
716
715
|
const self = hiddenPairs.find(p => p.name === agent);
|
|
717
716
|
agentRuleSectionsToEmit = self ? [`## ${self.name}\n\n${self.body}`] : [];
|
|
718
717
|
agentSectionsToEmit = agentSections.filter(s =>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Internal hidden agents — Mixdog-managed, user-untouchable.
|
|
3
3
|
*
|
|
4
4
|
* Unlike public workflow agents, these hidden agents are NEVER exposed to callers of the `agent` tool. They are
|
|
5
|
-
* invoked only by internal handlers (
|
|
5
|
+
* invoked only by internal handlers (recall / search) and carry
|
|
6
6
|
* their own system prompt + tool-set policy.
|
|
7
7
|
*
|
|
8
8
|
* Lookup order (agent-dispatch.resolveMaintenanceRoute):
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* found" error rather than silently mis-dispatching.
|
|
21
21
|
*
|
|
22
22
|
* Kind classification:
|
|
23
|
-
* - 'retrieval' : short-lived hidden retrieval agents
|
|
23
|
+
* - 'retrieval' : short-lived hidden retrieval agents.
|
|
24
24
|
* - 'maintenance' : background-trigger hidden agents (memory cycle and
|
|
25
25
|
* title generation). Receive only their own self section.
|
|
26
26
|
*
|
|
@@ -184,7 +184,7 @@ export function listHiddenAgentsByKind(kind) {
|
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
186
|
* Return the agents/<name>.md sections a hidden agent shares in its BP2 catalog
|
|
187
|
-
* (in addition to its own self section). Drives
|
|
187
|
+
* (in addition to its own self section). Drives hidden-role cache
|
|
188
188
|
* alignment declaratively instead of a hard-coded agent-name branch in
|
|
189
189
|
* collect.mjs. Returns [] when the agent declares none.
|
|
190
190
|
*/
|