mixdog 0.9.1 → 0.9.3
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 +9 -1
- package/scripts/_bench-cwc.json +20 -0
- package/scripts/agent-loop-policy-test.mjs +37 -0
- package/scripts/agent-parallel-smoke.mjs +54 -10
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/background-task-meta-smoke.mjs +1 -1
- package/scripts/bench-run.mjs +262 -0
- package/scripts/build-tui.mjs +13 -1
- package/scripts/compact-smoke.mjs +12 -0
- package/scripts/compact-trigger-migration-smoke.mjs +67 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
- package/scripts/internal-comms-bench.mjs +727 -0
- package/scripts/internal-comms-smoke.mjs +75 -0
- package/scripts/lead-workflow-smoke.mjs +4 -4
- package/scripts/live-worker-smoke.mjs +9 -9
- package/scripts/output-style-bench.mjs +285 -0
- package/scripts/output-style-smoke.mjs +13 -10
- package/scripts/patch-replay.mjs +90 -0
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-stream-stall-test.mjs +276 -0
- package/scripts/provider-toolcall-test.mjs +599 -1
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/routing-corpus.mjs +281 -0
- package/scripts/session-bench.mjs +1526 -0
- package/scripts/session-diag.mjs +595 -0
- package/scripts/task-bench.mjs +207 -0
- package/scripts/tool-failures.mjs +6 -6
- package/scripts/tool-smoke.mjs +310 -67
- package/scripts/toolcall-args-test.mjs +81 -0
- package/src/agents/debugger/AGENT.md +4 -4
- package/src/agents/heavy-worker/AGENT.md +20 -9
- package/src/agents/reviewer/AGENT.md +4 -4
- package/src/agents/worker/AGENT.md +17 -9
- package/src/app.mjs +10 -6
- package/src/defaults/{hidden-roles.json → agents.json} +7 -7
- package/src/examples/schedules/SCHEDULE.example.md +32 -0
- package/src/examples/webhooks/WEBHOOK.example.md +40 -0
- package/src/headless-role.mjs +14 -14
- package/src/help.mjs +1 -0
- package/src/lib/rules-builder.cjs +32 -54
- package/src/mixdog-session-runtime.mjs +1040 -2036
- package/src/output-styles/default.md +12 -7
- package/src/output-styles/minimal.md +25 -0
- package/src/output-styles/oneline.md +21 -0
- package/src/output-styles/simple.md +10 -9
- package/src/repl.mjs +17 -7
- package/src/rules/agent/00-common.md +7 -5
- package/src/rules/agent/30-explorer.md +8 -12
- package/src/rules/lead/01-general.md +3 -1
- package/src/rules/lead/lead-tool.md +13 -2
- package/src/rules/shared/01-tool.md +23 -12
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
- package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
- package/src/runtime/agent/orchestrator/config.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +182 -67
- package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
- package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
- package/src/runtime/agent/orchestrator/mcp/client.mjs +100 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +313 -84
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +104 -38
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +28 -33
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +227 -31
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +83 -6
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +229 -115
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +213 -33
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +49 -17
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +22 -17
- package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +262 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +513 -1000
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +227 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +137 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +232 -1152
- package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -24
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +162 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +14 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +23 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +50 -39
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +70 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +497 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1192 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +39 -4189
- package/src/runtime/agent/orchestrator/tools/patch.mjs +119 -5
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/channels/backends/discord.mjs +99 -9
- package/src/runtime/channels/backends/telegram.mjs +501 -0
- package/src/runtime/channels/index.mjs +437 -1439
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/config.mjs +54 -2
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +88 -67
- package/src/runtime/channels/lib/runtime-paths.mjs +29 -0
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +280 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +19 -1
- package/src/runtime/channels/lib/webhook.mjs +59 -31
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +465 -345
- package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
- package/src/runtime/memory/lib/core-memory-store.mjs +352 -2
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2.mjs +65 -9
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +121 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/recall-format.mjs +183 -0
- package/src/runtime/memory/lib/session-ingest.mjs +107 -0
- package/src/runtime/memory/lib/trace-store.mjs +69 -22
- package/src/runtime/memory/tool-defs.mjs +10 -7
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/channel-notification-routing.mjs +12 -0
- package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
- package/src/runtime/shared/config.mjs +9 -0
- package/src/runtime/shared/llm/http-agent.mjs +12 -5
- package/src/runtime/shared/schedules-store.mjs +21 -19
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/task-notification-envelope.test.mjs +107 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-surface.mjs +98 -13
- package/src/runtime/shared/transcript-writer.mjs +156 -0
- package/src/runtime/shared/update-checker.mjs +214 -0
- package/src/session-runtime/config-helpers.mjs +209 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/output-styles.mjs +124 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool.mjs +302 -117
- package/src/standalone/channel-admin.mjs +133 -40
- package/src/standalone/channel-worker.mjs +10 -292
- package/src/standalone/explore-tool.mjs +12 -5
- package/src/standalone/hook-bus.mjs +165 -8
- package/src/standalone/memory-runtime-proxy.mjs +3 -1
- package/src/standalone/opencode-go-login.mjs +121 -0
- package/src/standalone/provider-admin.mjs +25 -3
- package/src/standalone/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2883 -778
- package/src/tui/components/ConfirmBar.jsx +47 -0
- package/src/tui/components/ContextPanel.jsx +5 -3
- package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
- package/src/tui/components/Markdown.jsx +22 -98
- package/src/tui/components/Message.jsx +14 -35
- package/src/tui/components/Picker.jsx +87 -12
- package/src/tui/components/PromptInput.jsx +355 -22
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +8 -5
- package/src/tui/components/Spinner.jsx +7 -7
- package/src/tui/components/StatusLine.jsx +40 -21
- package/src/tui/components/TextEntryPanel.jsx +51 -7
- package/src/tui/components/ToolExecution.jsx +183 -101
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +161 -23
- package/src/tui/components/tool-output-format.test.mjs +87 -0
- package/src/tui/display-width.mjs +69 -0
- package/src/tui/display-width.test.mjs +35 -0
- package/src/tui/dist/index.mjs +6731 -2333
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +569 -948
- package/src/tui/index.jsx +117 -7
- package/src/tui/input-editing.mjs +58 -8
- package/src/tui/input-editing.selection.test.mjs +75 -0
- package/src/tui/keyboard-protocol.mjs +42 -0
- package/src/tui/lib/voice-recorder.mjs +469 -0
- package/src/tui/markdown/format-token.mjs +128 -76
- package/src/tui/markdown/format-token.test.mjs +61 -19
- package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
- package/src/tui/markdown/render-ansi.test.mjs +1 -1
- package/src/tui/markdown/streaming-markdown.mjs +167 -0
- package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
- package/src/tui/markdown/table-layout.mjs +9 -9
- package/src/tui/paste-attachments.mjs +36 -9
- package/src/tui/paste-fix.test.mjs +119 -0
- package/src/tui/prompt-history-store.mjs +129 -0
- package/src/tui/prompt-history-store.test.mjs +52 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
- package/src/tui/theme.mjs +41 -657
- package/src/tui/themes/base.mjs +86 -0
- package/src/tui/themes/basic.mjs +85 -0
- package/src/tui/themes/catppuccin.mjs +72 -0
- package/src/tui/themes/dracula.mjs +70 -0
- package/src/tui/themes/everforest.mjs +71 -0
- package/src/tui/themes/gruvbox.mjs +71 -0
- package/src/tui/themes/index.mjs +71 -0
- package/src/tui/themes/indigo.mjs +78 -0
- package/src/tui/themes/kanagawa.mjs +80 -0
- package/src/tui/themes/light.mjs +81 -0
- package/src/tui/themes/nord.mjs +72 -0
- package/src/tui/themes/onedark.mjs +16 -0
- package/src/tui/themes/rosepine.mjs +70 -0
- package/src/tui/themes/teal.mjs +80 -0
- package/src/tui/themes/tokyonight.mjs +79 -0
- package/src/tui/themes/utils.mjs +106 -0
- package/src/tui/themes/warm.mjs +79 -0
- package/src/tui/transcript-tool-failures.mjs +13 -2
- package/src/ui/markdown.mjs +1 -1
- package/src/ui/model-display.mjs +2 -2
- package/src/ui/statusline.mjs +75 -27
- package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
- package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
- package/src/workflows/default/WORKFLOW.md +46 -12
- package/src/workflows/sequential/WORKFLOW.md +51 -0
- package/src/workflows/solo/WORKFLOW.md +12 -1
- package/vendor/ink/build/display-width.js +62 -0
- package/vendor/ink/build/ink.js +100 -12
- package/vendor/ink/build/measure-text.js +4 -1
- package/vendor/ink/build/output.js +115 -9
- package/vendor/ink/build/render-node-to-output.js +4 -1
- package/vendor/ink/build/render.js +4 -0
- package/src/output-styles/extreme-simple.md +0 -20
- package/src/rules/lead/04-workflow.md +0 -51
- package/src/workflows/default/workflow.json +0 -13
- package/src/workflows/solo/workflow.json +0 -7
|
@@ -21,10 +21,12 @@ import {
|
|
|
21
21
|
isInvalidToolArgsMarker,
|
|
22
22
|
formatInvalidToolArgsResult,
|
|
23
23
|
} from '../src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs';
|
|
24
|
+
import { parseSSEStream } from '../src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs';
|
|
24
25
|
import { classifyError } from '../src/runtime/agent/orchestrator/providers/retry-classifier.mjs';
|
|
25
26
|
|
|
26
27
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27
28
|
const STREAM_SRC = resolve(__dirname, '../src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs');
|
|
29
|
+
const UTF8 = new TextEncoder();
|
|
28
30
|
|
|
29
31
|
// Captures the synchronous throw of `fn` and returns the Error, failing if none.
|
|
30
32
|
function captureThrow(fn) {
|
|
@@ -148,3 +150,82 @@ test('retry-classifier: truncated stream (no finish) → transient (preserved be
|
|
|
148
150
|
parseCompletedToolCallArgumentsJson('{', 'test'));
|
|
149
151
|
assert.equal(classifyError(transient), 'transient');
|
|
150
152
|
});
|
|
153
|
+
|
|
154
|
+
function responseFromSseText(text) {
|
|
155
|
+
return {
|
|
156
|
+
body: new ReadableStream({
|
|
157
|
+
start(controller) {
|
|
158
|
+
controller.enqueue(UTF8.encode(text));
|
|
159
|
+
controller.close();
|
|
160
|
+
},
|
|
161
|
+
}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function livePingOnlyResponse(intervalMs = 5) {
|
|
166
|
+
let timer = null;
|
|
167
|
+
return {
|
|
168
|
+
body: new ReadableStream({
|
|
169
|
+
start(controller) {
|
|
170
|
+
timer = setInterval(() => {
|
|
171
|
+
try { controller.enqueue(UTF8.encode(':ping\n\n')); }
|
|
172
|
+
catch { if (timer) clearInterval(timer); }
|
|
173
|
+
}, intervalMs);
|
|
174
|
+
},
|
|
175
|
+
cancel() {
|
|
176
|
+
if (timer) clearInterval(timer);
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
test('anthropic SSE: comments do not count as stream progress', async () => {
|
|
183
|
+
const state = { firstMessageTimeoutMs: 100 };
|
|
184
|
+
let deltas = 0;
|
|
185
|
+
const result = await parseSSEStream(
|
|
186
|
+
responseFromSseText([
|
|
187
|
+
':ping',
|
|
188
|
+
'',
|
|
189
|
+
'event: message_start',
|
|
190
|
+
'data: {"type":"message_start","message":{"model":"claude-test","usage":{"input_tokens":1}}}',
|
|
191
|
+
'',
|
|
192
|
+
'event: content_block_delta',
|
|
193
|
+
'data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"hi"}}',
|
|
194
|
+
'',
|
|
195
|
+
'event: message_stop',
|
|
196
|
+
'data: {"type":"message_stop"}',
|
|
197
|
+
'',
|
|
198
|
+
].join('\n')),
|
|
199
|
+
null,
|
|
200
|
+
null,
|
|
201
|
+
() => { deltas += 1; },
|
|
202
|
+
null,
|
|
203
|
+
state,
|
|
204
|
+
null,
|
|
205
|
+
);
|
|
206
|
+
assert.equal(result.content, 'hi');
|
|
207
|
+
assert.equal(deltas, 1, 'only the text delta should count as semantic progress');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test('anthropic SSE: ping-only stream times out before empty-stream guard can hang', async () => {
|
|
211
|
+
const controller = new AbortController();
|
|
212
|
+
let deltas = 0;
|
|
213
|
+
await assert.rejects(
|
|
214
|
+
() => parseSSEStream(
|
|
215
|
+
livePingOnlyResponse(),
|
|
216
|
+
controller.signal,
|
|
217
|
+
(reason) => controller.abort(reason),
|
|
218
|
+
() => { deltas += 1; },
|
|
219
|
+
null,
|
|
220
|
+
{ firstMessageTimeoutMs: 30 },
|
|
221
|
+
null,
|
|
222
|
+
),
|
|
223
|
+
(err) => {
|
|
224
|
+
assert.equal(err.code, 'EEMPTYSTREAM');
|
|
225
|
+
assert.equal(err.isEmptyStream, true);
|
|
226
|
+
assert.equal(err.firstByteTimeout, true);
|
|
227
|
+
return true;
|
|
228
|
+
},
|
|
229
|
+
);
|
|
230
|
+
assert.equal(deltas, 0, 'SSE comments must not refresh semantic stream progress');
|
|
231
|
+
});
|
|
@@ -4,8 +4,8 @@ permission: read
|
|
|
4
4
|
|
|
5
5
|
# Debugger
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Root-cause analysis agent.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Smallest confirmed cause chain before fixes. Return likely cause, evidence
|
|
10
|
+
(`file:line`), smallest next check/fix. Mark confirmed facts vs inferences;
|
|
11
|
+
avoid broad speculation.
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
---
|
|
2
|
-
permission: read-write
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Heavy Worker
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
---
|
|
2
|
+
permission: read-write
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Heavy Worker
|
|
6
|
+
Broad implementation agent.
|
|
7
|
+
|
|
8
|
+
Bounded slices; smallest coherent change, not rewrite. Stop: unclear scope,
|
|
9
|
+
growing blast radius, or Lead-only verification.
|
|
10
|
+
|
|
11
|
+
EDIT-FIRST DISCIPLINE. Survey the slice with ONE batched read/grep round,
|
|
12
|
+
then start patching the first bounded piece — broad scope means edit
|
|
13
|
+
incrementally, not read exhaustively. NEVER "one more confirming read": if
|
|
14
|
+
an anchor is plausible, the next call is `apply_patch`. 3+ consecutive
|
|
15
|
+
read-only calls without an edit = stalling — patch the piece you understand
|
|
16
|
+
or stop and report blocked. Self-check comes AFTER edits; deep verification
|
|
17
|
+
is Lead's.
|
|
18
|
+
|
|
19
|
+
Minimal checks + how-to-verify.
|
|
20
|
+
|
|
@@ -4,8 +4,8 @@ permission: read
|
|
|
4
4
|
|
|
5
5
|
# Reviewer
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Regression/risk review agent.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
material residual risk
|
|
9
|
+
Find actionable correctness/regression/security/verification risks. Findings
|
|
10
|
+
first, severity-ordered, one line with `file:line`; skip non-risky nits. If
|
|
11
|
+
clean, one line + only material residual risk.
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
---
|
|
2
|
-
permission: read-write
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Worker
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
---
|
|
2
|
+
permission: read-write
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Worker
|
|
6
|
+
Scoped implementation agent.
|
|
7
|
+
|
|
8
|
+
Smallest scoped change; no drive-by cleanup. Stop when done/blocked.
|
|
9
|
+
|
|
10
|
+
EDIT-FIRST DISCIPLINE. Brief anchors (`file:line`) are pre-verified — trust
|
|
11
|
+
them and patch. No anchor: locate with AT MOST 1-2 reads, then edit. NEVER
|
|
12
|
+
"one more confirming read": if you know the file and the change, the next
|
|
13
|
+
call is `apply_patch`. 3+ read-only calls without an edit = you are stalling
|
|
14
|
+
— either patch now or return blocked with what's missing. Confidence
|
|
15
|
+
threshold is "plausible", not "proven"; self-check comes AFTER the edit, and
|
|
16
|
+
Lead/Reviewer own final verification.
|
|
17
|
+
|
package/src/app.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { performance } from 'node:perf_hooks';
|
|
|
5
5
|
|
|
6
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
const VALUE_OPTIONS = new Set(['--provider', '--model']);
|
|
8
|
-
const FLAG_OPTIONS = new Set(['--readonly', '--help', '-h', '--plain', '--react']);
|
|
8
|
+
const FLAG_OPTIONS = new Set(['--readonly', '--help', '-h', '--plain', '--react', '--remote', '--onboarding']);
|
|
9
9
|
const HEADLESS_ROLE_ALIASES = new Map([
|
|
10
10
|
['explorer', 'explore'],
|
|
11
11
|
['explore', 'explore'],
|
|
@@ -72,7 +72,7 @@ function positionalArgs(argv) {
|
|
|
72
72
|
return out;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function
|
|
75
|
+
function normalizeHeadlessAgent(value) {
|
|
76
76
|
const key = String(value || '').trim().toLowerCase().replace(/[\s_]+/g, '-');
|
|
77
77
|
return HEADLESS_ROLE_ALIASES.get(key) || null;
|
|
78
78
|
}
|
|
@@ -85,11 +85,11 @@ export function parseHeadlessRoleCommand(argv = []) {
|
|
|
85
85
|
return { error: 'usage: mixdog <role> <message...>' };
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const
|
|
89
|
-
if (!
|
|
88
|
+
const agent = normalizeHeadlessAgent(args[0]);
|
|
89
|
+
if (!agent) return null;
|
|
90
90
|
const message = args.slice(1).join(' ').trim();
|
|
91
91
|
if (!message) return { error: `usage: mixdog ${args[0]} <message...>` };
|
|
92
|
-
return {
|
|
92
|
+
return { agent, message };
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/**
|
|
@@ -110,10 +110,14 @@ export async function run(argv = []) {
|
|
|
110
110
|
const provIdx = argv.indexOf('--provider');
|
|
111
111
|
const modelIdx = argv.indexOf('--model');
|
|
112
112
|
const toolMode = argv.includes('--readonly') ? 'readonly' : 'full';
|
|
113
|
+
const remote = argv.includes('--remote');
|
|
114
|
+
const forceOnboarding = argv.includes('--onboarding');
|
|
113
115
|
const opts = {
|
|
114
116
|
provider: provIdx >= 0 ? argv[provIdx + 1] : undefined,
|
|
115
117
|
model: modelIdx >= 0 ? argv[modelIdx + 1] : undefined,
|
|
116
118
|
toolMode,
|
|
119
|
+
remote,
|
|
120
|
+
forceOnboarding,
|
|
117
121
|
};
|
|
118
122
|
|
|
119
123
|
// `--help` / `-h`: keep this path tiny; do not import the REPL/runtime stack.
|
|
@@ -142,7 +146,7 @@ export async function run(argv = []) {
|
|
|
142
146
|
if (headless) {
|
|
143
147
|
const { runHeadlessRole } = await import('./headless-role.mjs');
|
|
144
148
|
return await runHeadlessRole({
|
|
145
|
-
|
|
149
|
+
agent: headless.agent,
|
|
146
150
|
message: headless.message,
|
|
147
151
|
provider: opts.provider,
|
|
148
152
|
model: opts.model,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"agents": [
|
|
3
3
|
{
|
|
4
|
-
"
|
|
4
|
+
"agent": "explorer",
|
|
5
5
|
"slot": "explore",
|
|
6
6
|
"systemFile": "rules/agent/30-explorer.md",
|
|
7
7
|
"description": "Filesystem navigation agent invoked by the `explore` MCP tool",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"stallCap": { "idleSeconds": 240, "toolRunningSeconds": 180 }
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
|
-
"
|
|
15
|
+
"agent": "cycle1-agent",
|
|
16
16
|
"slot": "cycle1",
|
|
17
17
|
"systemFile": "rules/agent/40-cycle1-agent.md",
|
|
18
18
|
"description": "Chunker/classifier invoked by memory-cycle runCycle1",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"stallCap": { "idleSeconds": 300, "toolRunningSeconds": 300 }
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
"
|
|
27
|
+
"agent": "cycle2-agent",
|
|
28
28
|
"slot": "cycle2",
|
|
29
29
|
"systemFile": "rules/agent/41-cycle2-agent.md",
|
|
30
30
|
"description": "Root re-scorer invoked by memory-cycle runCycle2",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"stallCap": { "idleSeconds": 300, "toolRunningSeconds": 300 }
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
"
|
|
39
|
+
"agent": "cycle3-agent",
|
|
40
40
|
"slot": "cycle3",
|
|
41
41
|
"systemFile": "rules/agent/42-cycle3-agent.md",
|
|
42
42
|
"description": "Core memory reviewer invoked by memory-cycle runCycle3",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"stallCap": { "idleSeconds": 300, "toolRunningSeconds": 300 }
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
"
|
|
51
|
+
"agent": "scheduler-task",
|
|
52
52
|
"slot": "scheduler",
|
|
53
53
|
"systemFile": "agents/scheduler-task/AGENT.md",
|
|
54
54
|
"description": "Scheduled-task executor invoked by scheduler tick",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"stallCap": { "idleSeconds": 600, "toolRunningSeconds": 600 }
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
"
|
|
64
|
+
"agent": "webhook-handler",
|
|
65
65
|
"slot": "webhook",
|
|
66
66
|
"systemFile": "agents/webhook-handler/AGENT.md",
|
|
67
67
|
"description": "Webhook payload handler invoked by inbound webhook events",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
time: 0 9 * * *
|
|
3
|
+
timezone: Asia/Seoul
|
|
4
|
+
days: weekday
|
|
5
|
+
channel: main
|
|
6
|
+
model: gpt-5
|
|
7
|
+
enabled: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Schedule instructions (prompt body)
|
|
11
|
+
|
|
12
|
+
This whole markdown body is the prompt the scheduler runs when the cron fires.
|
|
13
|
+
Everything above the second `---` is frontmatter metadata; everything below is
|
|
14
|
+
the instructions.
|
|
15
|
+
|
|
16
|
+
Frontmatter keys:
|
|
17
|
+
|
|
18
|
+
- `time` — required. 5- or 6-field cron expression (e.g. `0 9 * * *`).
|
|
19
|
+
- `timezone` — optional IANA tz (e.g. `Asia/Seoul`); host-local when omitted.
|
|
20
|
+
- `days` — optional; omit for `daily`. Allowed values: `weekday`, `weekend`, or
|
|
21
|
+
a comma list of day abbreviations (`mon,tue,wed,thu,fri,sat,sun`). Written
|
|
22
|
+
only when not `daily`.
|
|
23
|
+
- `channel` — optional channel label. WITH a channel the run dispatches to that
|
|
24
|
+
channel (non-interactive) and REQUIRES `model`; WITHOUT it the run injects
|
|
25
|
+
into the current session (interactive).
|
|
26
|
+
- `model` — required when `channel` is set; the preset id used for dispatch.
|
|
27
|
+
- `enabled` — optional; written `false` to disable. Missing/anything-else means
|
|
28
|
+
enabled. The reader casts this string to a boolean.
|
|
29
|
+
|
|
30
|
+
Storage layout: `<data>/schedules/<name>/SCHEDULE.md` — one file per schedule.
|
|
31
|
+
This `.example.md` is documentation only; the readers match `SCHEDULE.md`
|
|
32
|
+
exactly, so this file is never loaded as a real schedule.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
parser: github
|
|
3
|
+
channel: main
|
|
4
|
+
model: gpt-5
|
|
5
|
+
role: webhook-handler
|
|
6
|
+
enabled: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Webhook instructions (prompt body)
|
|
10
|
+
|
|
11
|
+
This markdown body is the handler prompt. On each verified delivery the webhook
|
|
12
|
+
payload is fenced as untrusted data and appended after these instructions.
|
|
13
|
+
Everything above the second `---` is frontmatter metadata; everything below is
|
|
14
|
+
the instructions.
|
|
15
|
+
|
|
16
|
+
Frontmatter keys:
|
|
17
|
+
|
|
18
|
+
- `parser` — required. One of `github`, `generic`, `stripe`, `sentry`. Selects
|
|
19
|
+
the signature header + verification scheme.
|
|
20
|
+
- `channel` — optional channel label. WITH a channel the delivery is dispatched
|
|
21
|
+
as a delegate (REQUIRES `model` + `role`) and reported to that channel;
|
|
22
|
+
WITHOUT it the payload is enqueued into the current session (interactive).
|
|
23
|
+
- `model` — required when `channel` is set; the preset id used for delegate
|
|
24
|
+
dispatch.
|
|
25
|
+
- `role` — user-workflow role for delegate mode; defaults to `webhook-handler`.
|
|
26
|
+
- `enabled` — optional; written `false` to disable (delivery rejected with 404).
|
|
27
|
+
Missing/anything-else means enabled. The reader casts this string to a boolean.
|
|
28
|
+
|
|
29
|
+
Secret storage: the HMAC secret is NOT a frontmatter key. It lives in a side
|
|
30
|
+
file `<data>/webhooks/<name>/secret` (plaintext, one line), autogenerated
|
|
31
|
+
(24 random bytes hex) when omitted at save time. Keeping it out of the lossy
|
|
32
|
+
`key: value` frontmatter lets an arbitrary user secret (quotes/colons/newlines)
|
|
33
|
+
round-trip losslessly and prevents enable/disable rewrites from corrupting it.
|
|
34
|
+
The admin list API never exposes the value — only `secretSet: true/false`.
|
|
35
|
+
|
|
36
|
+
Storage layout: `<data>/webhooks/<name>/WEBHOOK.md` — one file per endpoint.
|
|
37
|
+
`secret` and `deliveries.jsonl` live alongside it and are managed separately.
|
|
38
|
+
This
|
|
39
|
+
`.example.md` is documentation only; the readers match `WEBHOOK.md` exactly, so
|
|
40
|
+
this file is never loaded as a real endpoint.
|
package/src/headless-role.mjs
CHANGED
|
@@ -19,16 +19,16 @@ function taskIdFromOutput(text) {
|
|
|
19
19
|
return clean(text).match(/agent task:\s*(\S+)/i)?.[1] || null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function makeTag(
|
|
23
|
-
return `headless-${
|
|
22
|
+
function makeTag(agent) {
|
|
23
|
+
return `headless-${agent}-${process.pid}-${Date.now()}`
|
|
24
24
|
.replace(/[^A-Za-z0-9_.-]+/g, '-')
|
|
25
25
|
.replace(/^-+|-+$/g, '');
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function buildHeadlessSpawnArgs({
|
|
28
|
+
export function buildHeadlessSpawnArgs({ agent, tag, cwd, message, provider, model } = {}) {
|
|
29
29
|
const spawnArgs = {
|
|
30
30
|
type: 'spawn',
|
|
31
|
-
|
|
31
|
+
agent: clean(agent),
|
|
32
32
|
tag,
|
|
33
33
|
cwd,
|
|
34
34
|
prompt: clean(message),
|
|
@@ -52,7 +52,7 @@ function buildAgentRunner(cwd) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export async function runHeadlessRole({
|
|
55
|
-
|
|
55
|
+
agent,
|
|
56
56
|
message,
|
|
57
57
|
provider,
|
|
58
58
|
model,
|
|
@@ -60,10 +60,10 @@ export async function runHeadlessRole({
|
|
|
60
60
|
write = (text) => stdout.write(text),
|
|
61
61
|
writeErr = (text) => stderr.write(text),
|
|
62
62
|
} = {}) {
|
|
63
|
-
const
|
|
63
|
+
const cleanAgent = clean(agent);
|
|
64
64
|
const cleanMessage = clean(message);
|
|
65
|
-
if (!
|
|
66
|
-
writeErr('mixdog:
|
|
65
|
+
if (!cleanAgent) {
|
|
66
|
+
writeErr('mixdog: agent is required\n');
|
|
67
67
|
return 1;
|
|
68
68
|
}
|
|
69
69
|
if (!cleanMessage) {
|
|
@@ -71,8 +71,8 @@ export async function runHeadlessRole({
|
|
|
71
71
|
return 1;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
const
|
|
75
|
-
const tag = makeTag(
|
|
74
|
+
const agentRunner = buildAgentRunner(cwd);
|
|
75
|
+
const tag = makeTag(cleanAgent);
|
|
76
76
|
const context = {
|
|
77
77
|
invocationSource: 'headless',
|
|
78
78
|
cwd,
|
|
@@ -80,7 +80,7 @@ export async function runHeadlessRole({
|
|
|
80
80
|
clientHostPid: process.pid,
|
|
81
81
|
};
|
|
82
82
|
const spawnArgs = buildHeadlessSpawnArgs({
|
|
83
|
-
|
|
83
|
+
agent: cleanAgent,
|
|
84
84
|
tag,
|
|
85
85
|
cwd,
|
|
86
86
|
message: cleanMessage,
|
|
@@ -91,7 +91,7 @@ export async function runHeadlessRole({
|
|
|
91
91
|
let taskId = null;
|
|
92
92
|
let lastOutput = '';
|
|
93
93
|
try {
|
|
94
|
-
const started = await
|
|
94
|
+
const started = await agentRunner.execute(spawnArgs, context);
|
|
95
95
|
lastOutput = clean(started);
|
|
96
96
|
taskId = taskIdFromOutput(started);
|
|
97
97
|
if (!taskId) {
|
|
@@ -100,7 +100,7 @@ export async function runHeadlessRole({
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
for (;;) {
|
|
103
|
-
lastOutput = clean(await
|
|
103
|
+
lastOutput = clean(await agentRunner.execute({ type: 'read', task_id: taskId }, context));
|
|
104
104
|
if (TERMINAL_STATUS_RE.test(lastOutput)) break;
|
|
105
105
|
await sleep(500);
|
|
106
106
|
}
|
|
@@ -109,7 +109,7 @@ export async function runHeadlessRole({
|
|
|
109
109
|
return FAILURE_STATUS_RE.test(lastOutput) ? 1 : 0;
|
|
110
110
|
} finally {
|
|
111
111
|
try {
|
|
112
|
-
await
|
|
112
|
+
await agentRunner.execute({ type: 'close', tag }, context);
|
|
113
113
|
} catch {
|
|
114
114
|
// Best-effort cleanup only; the command result above is the useful signal.
|
|
115
115
|
}
|
package/src/help.mjs
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* Source files (rules/):
|
|
22
22
|
* - shared/01-tool.md — universal tool policy (Lead + agent BP1, identical full set)
|
|
23
23
|
* - lead/lead-tool.md — Lead-specific control-tower / delegation / ToolSearch guidance
|
|
24
|
-
* - lead/01-
|
|
24
|
+
* - lead/01-02 — Lead general / channels
|
|
25
25
|
* - output-styles/<name>.md — Lead output style, selected by config outputStyle
|
|
26
26
|
* - agent/00-common.md — agent common behavior + universal worker contract (BP2)
|
|
27
|
-
* - agent/10..50-*.md — per-hidden-
|
|
27
|
+
* - agent/10..50-*.md — per-hidden-agent bodies (consumed by loadScopedRoleInstructions)
|
|
28
28
|
*
|
|
29
29
|
* Core memory snapshot is injected separately from the memory worker (pgdata)
|
|
30
30
|
* (Lead only).
|
|
@@ -184,29 +184,29 @@ function loadOutputStyle({ PLUGIN_ROOT, DATA_DIR }) {
|
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
186
|
* Resolve the DATA_DIR subdir whose *.md instruction tree is sent as
|
|
187
|
-
* BP4-adjacent user/task data, from the
|
|
188
|
-
* defaults/
|
|
187
|
+
* BP4-adjacent user/task data, from the agent's `instructionDir` metadata in
|
|
188
|
+
* defaults/agents.json. Returns null when the agent declares none.
|
|
189
189
|
*
|
|
190
|
-
* Mirrors internal-
|
|
190
|
+
* Mirrors internal-agents.mjs getAgentInstructionDir — rules-builder is CommonJS
|
|
191
191
|
* and cannot import the ESM module, so it reads the same source of truth
|
|
192
192
|
* directly. Keeps the webhook-handler→webhooks / scheduler-task→schedules
|
|
193
|
-
* mapping declarative instead of a hard-coded
|
|
193
|
+
* mapping declarative instead of a hard-coded agent-name ternary.
|
|
194
194
|
*
|
|
195
195
|
* @param {string} mixdogRoot
|
|
196
|
-
* @param {string}
|
|
196
|
+
* @param {string} agent
|
|
197
197
|
* @returns {string|null}
|
|
198
198
|
*/
|
|
199
|
-
function
|
|
200
|
-
if (!mixdogRoot || !
|
|
201
|
-
const metaPath = path.join(mixdogRoot, 'defaults', '
|
|
199
|
+
function resolveAgentInstructionDir(mixdogRoot, agent) {
|
|
200
|
+
if (!mixdogRoot || !agent) return null;
|
|
201
|
+
const metaPath = path.join(mixdogRoot, 'defaults', 'agents.json');
|
|
202
202
|
let raw;
|
|
203
203
|
try {
|
|
204
204
|
raw = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
|
|
205
205
|
} catch (e) {
|
|
206
|
-
throw new Error(`[rules-builder] failed to read/parse
|
|
206
|
+
throw new Error(`[rules-builder] failed to read/parse agents.json at ${metaPath}: ${e.message}`);
|
|
207
207
|
}
|
|
208
|
-
for (const entry of (raw.
|
|
209
|
-
if (entry && entry.
|
|
208
|
+
for (const entry of (raw.agents || [])) {
|
|
209
|
+
if (entry && entry.agent === agent) {
|
|
210
210
|
const dir = typeof entry.instructionDir === 'string' ? entry.instructionDir.trim() : '';
|
|
211
211
|
return dir || null;
|
|
212
212
|
}
|
|
@@ -247,34 +247,15 @@ function composeUserAddressBullet(memoryConfig) {
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
function splitLeadGeneral(general, addressBullet = '') {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
inMeta = true;
|
|
260
|
-
}
|
|
261
|
-
metaLines.push(line);
|
|
262
|
-
} else {
|
|
263
|
-
roleLines.push(line);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
if (addressBullet) {
|
|
267
|
-
if (!inMeta) {
|
|
268
|
-
metaLines.push('# General');
|
|
269
|
-
metaLines.push('');
|
|
270
|
-
inMeta = true;
|
|
271
|
-
}
|
|
272
|
-
metaLines.push(addressBullet);
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
role: roleLines.join('\n').trim(),
|
|
276
|
-
meta: metaLines.join('\n').trim(),
|
|
277
|
-
};
|
|
250
|
+
// Language is owned solely by the `# Language` section (buildLanguageSection);
|
|
251
|
+
// general.md never carries a language line, so there is no language content to
|
|
252
|
+
// promote into the meta layer here. The only meta-tier content this split
|
|
253
|
+
// emits is the optional user address-form bullet.
|
|
254
|
+
const role = String(general || '').trim();
|
|
255
|
+
const meta = addressBullet
|
|
256
|
+
? ['# General', '', addressBullet].join('\n').trim()
|
|
257
|
+
: '';
|
|
258
|
+
return { role, meta };
|
|
278
259
|
}
|
|
279
260
|
|
|
280
261
|
function buildSharedToolContent({ PLUGIN_ROOT }) {
|
|
@@ -299,9 +280,6 @@ function buildLeadRoleContent({ PLUGIN_ROOT, DATA_DIR }) {
|
|
|
299
280
|
const channels = readOptional(path.join(LEAD_DIR, '02-channels.md'));
|
|
300
281
|
if (channels) parts.push(channels);
|
|
301
282
|
|
|
302
|
-
const workflow = readOptional(path.join(LEAD_DIR, '04-workflow.md'));
|
|
303
|
-
if (workflow) parts.push(workflow);
|
|
304
|
-
|
|
305
283
|
return parts.join('\n\n');
|
|
306
284
|
}
|
|
307
285
|
|
|
@@ -420,26 +398,26 @@ function buildAgentRetrievalInjectionContent() {
|
|
|
420
398
|
* @param {object} opts
|
|
421
399
|
* @param {string} opts.PLUGIN_ROOT
|
|
422
400
|
* @param {string} opts.DATA_DIR
|
|
423
|
-
* @param {string|null} opts.
|
|
401
|
+
* @param {string|null} opts.currentAgent
|
|
424
402
|
* @returns {string}
|
|
425
403
|
*/
|
|
426
|
-
function buildAgentRoleSpecificContent({ PLUGIN_ROOT, DATA_DIR,
|
|
427
|
-
if (!
|
|
404
|
+
function buildAgentRoleSpecificContent({ PLUGIN_ROOT, DATA_DIR, currentAgent }) {
|
|
405
|
+
if (!currentAgent) return '';
|
|
428
406
|
const parts = [];
|
|
429
407
|
|
|
430
|
-
// The
|
|
431
|
-
// → schedules) is declared via `instructionDir` in defaults/
|
|
432
|
-
// rather than hard-coded here, so adding a new inbound-event
|
|
408
|
+
// The agent's instruction subdir (webhook-handler → webhooks, scheduler-task
|
|
409
|
+
// → schedules) is declared via `instructionDir` in defaults/agents.json
|
|
410
|
+
// rather than hard-coded here, so adding a new inbound-event agent needs only
|
|
433
411
|
// a metadata entry.
|
|
434
|
-
const
|
|
435
|
-
if (
|
|
436
|
-
const dir = path.join(DATA_DIR,
|
|
412
|
+
const subdirForAgent = resolveAgentInstructionDir(PLUGIN_ROOT, currentAgent);
|
|
413
|
+
if (subdirForAgent) {
|
|
414
|
+
const dir = path.join(DATA_DIR, subdirForAgent);
|
|
437
415
|
const collected = collectMarkdownFilesRecursive(dir);
|
|
438
416
|
if (collected.length > 0) {
|
|
439
417
|
collected.sort();
|
|
440
418
|
const blocks = collected.map(f => stripFrontmatter(readOptional(f))).filter(Boolean);
|
|
441
419
|
if (blocks.length > 0) {
|
|
442
|
-
parts.push([`# Agent ${
|
|
420
|
+
parts.push([`# Agent ${subdirForAgent}`, '', blocks.join('\n\n')].join('\n'));
|
|
443
421
|
}
|
|
444
422
|
}
|
|
445
423
|
}
|