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
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// Workflow/agent pack loading + route resolution, and search-route
|
|
2
|
+
// normalization. Roots/dataDir and config-dependent helpers are injected to
|
|
3
|
+
// keep this module free of the runtime's path/provider constants.
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
6
|
+
import { clean } from './session-text.mjs';
|
|
7
|
+
import { normalizeEffortInput } from './effort.mjs';
|
|
8
|
+
import { isLikelyRawModelId } from './config-helpers.mjs';
|
|
9
|
+
import { readTextSafe, readJsonSafe } from './fs-utils.mjs';
|
|
10
|
+
|
|
11
|
+
export const WORKFLOW_ROUTE_SLOTS = ['lead', 'agent', 'explorer', 'memory'];
|
|
12
|
+
export const FIXED_AGENT_SLOTS = Object.freeze([
|
|
13
|
+
{ id: 'explore', label: 'Explore', description: 'Broad repository exploration', workflowSlot: 'explorer' },
|
|
14
|
+
{ id: 'maintainer', label: 'Maintainer', description: 'Background memory and upkeep', workflowSlot: 'memory' },
|
|
15
|
+
{ id: 'worker', label: 'Worker', description: 'Scoped implementation' },
|
|
16
|
+
{ id: 'heavy-worker', label: 'Heavy Worker', description: 'Broad or multi-file implementation' },
|
|
17
|
+
{ id: 'reviewer', label: 'Reviewer', description: 'Diff review and risk checks' },
|
|
18
|
+
{ id: 'debugger', label: 'Debugger', description: 'Root-cause analysis and failure tracing' },
|
|
19
|
+
]);
|
|
20
|
+
const AGENT_ROLE_IDS = new Set(FIXED_AGENT_SLOTS.map((agent) => agent.id));
|
|
21
|
+
const DEFAULT_WORKFLOW_ID = 'default';
|
|
22
|
+
|
|
23
|
+
const SEARCH_CAPABLE_PROVIDERS = new Set([
|
|
24
|
+
'openai-oauth', 'openai', 'grok-oauth', 'xai', 'gemini', 'anthropic', 'anthropic-oauth',
|
|
25
|
+
]);
|
|
26
|
+
export const SEARCH_DEFAULT_PROVIDER = 'default';
|
|
27
|
+
export const SEARCH_DEFAULT_MODEL = 'default';
|
|
28
|
+
const SEARCH_PROVIDER_ALIASES = Object.freeze({
|
|
29
|
+
'openai-api': 'openai',
|
|
30
|
+
'xai-api': 'xai',
|
|
31
|
+
'gemini-api': 'gemini',
|
|
32
|
+
'anthropic-api': 'anthropic',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const agentDefinitionCache = new Map();
|
|
36
|
+
const AGENT_DEFINITION_CACHE_LIMIT = 64;
|
|
37
|
+
function setAgentDefinitionCache(key, value) {
|
|
38
|
+
if (!agentDefinitionCache.has(key) && agentDefinitionCache.size >= AGENT_DEFINITION_CACHE_LIMIT) {
|
|
39
|
+
const oldestKey = agentDefinitionCache.keys().next().value;
|
|
40
|
+
agentDefinitionCache.delete(oldestKey);
|
|
41
|
+
}
|
|
42
|
+
agentDefinitionCache.set(key, value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function workflowPresetId(slot) {
|
|
46
|
+
return `workflow-${slot}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function workflowPresetName(slot) {
|
|
50
|
+
return `WORKFLOW ${String(slot || '').toUpperCase()}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function agentPresetSlot(agentId) {
|
|
54
|
+
return `agent-${String(agentId || '').replace(/[^a-z0-9_.-]+/gi, '-').toLowerCase()}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function normalizeAgentId(value) {
|
|
58
|
+
const id = clean(value).toLowerCase().replace(/[\s_]+/g, '-');
|
|
59
|
+
if (id === 'explorer') return 'explore';
|
|
60
|
+
if (id === 'maint' || id === 'maintenance' || id === 'memory') return 'maintainer';
|
|
61
|
+
if (id === 'heavy' || id === 'heavyworker') return 'heavy-worker';
|
|
62
|
+
if (id === 'review') return 'reviewer';
|
|
63
|
+
if (id === 'debug') return 'debugger';
|
|
64
|
+
return AGENT_ROLE_IDS.has(id) ? id : '';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function normalizeWorkflowId(value, fallback = '') {
|
|
68
|
+
const id = clean(value).toLowerCase().replace(/[\s_]+/g, '-');
|
|
69
|
+
return /^[a-z0-9][a-z0-9_.-]*$/.test(id) ? id : fallback;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// A workflow/agent pack loader is created per data/root layout via
|
|
73
|
+
// createWorkflowHelpers, and the config-aware route helpers via
|
|
74
|
+
// createWorkflowRouteHelpers.
|
|
75
|
+
export function createWorkflowHelpers({ rootDir, dataDir, readMarkdownDocument, normalizeAgentPermissionOrNone }) {
|
|
76
|
+
function workflowSourceDirs(dir) {
|
|
77
|
+
return [
|
|
78
|
+
{ root: join(rootDir, 'workflows'), source: 'built-in' },
|
|
79
|
+
{ root: join(dir || dataDir, 'workflows'), source: 'user' },
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function agentSourceDirs(dir, id) {
|
|
84
|
+
return [
|
|
85
|
+
join(dir || dataDir, 'agents', id),
|
|
86
|
+
join(rootDir, 'agents', id),
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function readWorkflowPackFromDir(dir, source = 'built-in', dirName = '') {
|
|
91
|
+
const entry = 'WORKFLOW.md';
|
|
92
|
+
const doc = readMarkdownDocument(readTextSafe(join(dir, entry)));
|
|
93
|
+
const body = doc.body;
|
|
94
|
+
if (!body) return null;
|
|
95
|
+
const fm = doc.frontmatter || {};
|
|
96
|
+
const id = normalizeWorkflowId(clean(fm.id) || dirName || basename(dir));
|
|
97
|
+
if (!id) return null;
|
|
98
|
+
const agentsConfigured = Object.prototype.hasOwnProperty.call(fm, 'agents');
|
|
99
|
+
return {
|
|
100
|
+
id,
|
|
101
|
+
name: clean(fm.name) || id,
|
|
102
|
+
description: clean(fm.description),
|
|
103
|
+
entry,
|
|
104
|
+
agentsConfigured,
|
|
105
|
+
agents: agentsConfigured
|
|
106
|
+
? String(fm.agents || '')
|
|
107
|
+
.split(',')
|
|
108
|
+
.map((agent) => normalizeAgentId(agent) || normalizeWorkflowId(agent))
|
|
109
|
+
.filter(Boolean)
|
|
110
|
+
: [],
|
|
111
|
+
body,
|
|
112
|
+
source,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function listWorkflowPacks(dir) {
|
|
117
|
+
const byId = new Map();
|
|
118
|
+
for (const { root, source } of workflowSourceDirs(dir)) {
|
|
119
|
+
if (!existsSync(root)) continue;
|
|
120
|
+
let entries = [];
|
|
121
|
+
try { entries = readdirSync(root, { withFileTypes: true }); } catch { entries = []; }
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
if (!entry.isDirectory()) continue;
|
|
124
|
+
const d = join(root, entry.name);
|
|
125
|
+
if (!existsSync(join(d, 'WORKFLOW.md'))) continue;
|
|
126
|
+
const pack = readWorkflowPackFromDir(d, source, entry.name);
|
|
127
|
+
if (pack) byId.set(pack.id, pack);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return [...byId.values()].sort((a, b) => {
|
|
131
|
+
if (a.id === DEFAULT_WORKFLOW_ID) return -1;
|
|
132
|
+
if (b.id === DEFAULT_WORKFLOW_ID) return 1;
|
|
133
|
+
return a.name.localeCompare(b.name);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function activeWorkflowId(config) {
|
|
138
|
+
return normalizeWorkflowId(config?.workflow?.active, DEFAULT_WORKFLOW_ID);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function loadWorkflowPack(dir, id) {
|
|
142
|
+
const wanted = normalizeWorkflowId(id, DEFAULT_WORKFLOW_ID);
|
|
143
|
+
for (const { root, source } of workflowSourceDirs(dir).reverse()) {
|
|
144
|
+
const pack = readWorkflowPackFromDir(join(root, wanted), source, wanted);
|
|
145
|
+
if (pack) return pack;
|
|
146
|
+
}
|
|
147
|
+
return readWorkflowPackFromDir(join(rootDir, 'workflows', DEFAULT_WORKFLOW_ID), 'built-in', DEFAULT_WORKFLOW_ID);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function workflowSummary(pack) {
|
|
151
|
+
const id = normalizeWorkflowId(pack?.id, DEFAULT_WORKFLOW_ID);
|
|
152
|
+
return {
|
|
153
|
+
id,
|
|
154
|
+
name: clean(pack?.name) || (id === DEFAULT_WORKFLOW_ID ? 'Default' : id),
|
|
155
|
+
description: clean(pack?.description),
|
|
156
|
+
source: clean(pack?.source),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function activeWorkflowSummary(config, dir) {
|
|
161
|
+
return workflowSummary(loadWorkflowPack(dir, activeWorkflowId(config)));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function loadAgentDefinition(dir, id) {
|
|
165
|
+
const agentId = normalizeAgentId(id) || normalizeWorkflowId(id);
|
|
166
|
+
if (!agentId) return null;
|
|
167
|
+
const cacheKey = `${dir || dataDir}\n${agentId}`;
|
|
168
|
+
if (agentDefinitionCache.has(cacheKey)) return agentDefinitionCache.get(cacheKey);
|
|
169
|
+
for (const d of agentSourceDirs(dir, agentId)) {
|
|
170
|
+
const manifest = readJsonSafe(join(d, 'agent.json')) || {};
|
|
171
|
+
const entry = clean(manifest.entry) || 'AGENT.md';
|
|
172
|
+
const doc = readMarkdownDocument(readTextSafe(join(d, entry)));
|
|
173
|
+
const body = doc.body;
|
|
174
|
+
if (!body) continue;
|
|
175
|
+
const definition = {
|
|
176
|
+
id: agentId,
|
|
177
|
+
name: clean(manifest.name) || FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.label || agentId,
|
|
178
|
+
description: clean(manifest.description) || FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.description || '',
|
|
179
|
+
permission: normalizeAgentPermissionOrNone(doc.frontmatter.permission),
|
|
180
|
+
frontmatter: doc.frontmatter,
|
|
181
|
+
body,
|
|
182
|
+
};
|
|
183
|
+
setAgentDefinitionCache(cacheKey, definition);
|
|
184
|
+
return definition;
|
|
185
|
+
}
|
|
186
|
+
const legacyDoc = readMarkdownDocument(readTextSafe(join(rootDir, 'agents', `${agentId}.md`)));
|
|
187
|
+
if (!legacyDoc.body) {
|
|
188
|
+
setAgentDefinitionCache(cacheKey, null);
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const definition = {
|
|
192
|
+
id: agentId,
|
|
193
|
+
name: FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.label || agentId,
|
|
194
|
+
description: '',
|
|
195
|
+
permission: normalizeAgentPermissionOrNone(legacyDoc.frontmatter.permission),
|
|
196
|
+
frontmatter: legacyDoc.frontmatter,
|
|
197
|
+
body: legacyDoc.body,
|
|
198
|
+
};
|
|
199
|
+
setAgentDefinitionCache(cacheKey, definition);
|
|
200
|
+
return definition;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function workflowContextBlock(config, dir) {
|
|
204
|
+
const pack = loadWorkflowPack(dir, activeWorkflowId(config));
|
|
205
|
+
if (!pack) return '';
|
|
206
|
+
const lines = [`# Active Workflow: ${pack.name}`];
|
|
207
|
+
if (pack.description) lines.push(pack.description);
|
|
208
|
+
lines.push(pack.body);
|
|
209
|
+
const agentIds = pack.agentsConfigured ? pack.agents : FIXED_AGENT_SLOTS.map((agent) => agent.id);
|
|
210
|
+
const agentBlocks = agentIds.map((id) => loadAgentDefinition(dir, id)).filter(Boolean);
|
|
211
|
+
if (agentBlocks.length) {
|
|
212
|
+
lines.push('# Available Agents');
|
|
213
|
+
for (const agent of agentBlocks) {
|
|
214
|
+
lines.push(`## ${agent.name} (${agent.id})`);
|
|
215
|
+
if (agent.description) lines.push(agent.description);
|
|
216
|
+
lines.push(agent.body);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return lines.join('\n\n');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
listWorkflowPacks,
|
|
224
|
+
activeWorkflowId,
|
|
225
|
+
loadWorkflowPack,
|
|
226
|
+
workflowSummary,
|
|
227
|
+
activeWorkflowSummary,
|
|
228
|
+
loadAgentDefinition,
|
|
229
|
+
workflowContextBlock,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function normalizeSearchProviderId(provider) {
|
|
234
|
+
const id = clean(provider);
|
|
235
|
+
return SEARCH_PROVIDER_ALIASES[id] || id;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function isDefaultSearchRouteConfig(routeLike = {}) {
|
|
239
|
+
return normalizeSearchProviderId(routeLike?.provider) === SEARCH_DEFAULT_PROVIDER
|
|
240
|
+
&& clean(routeLike?.model).toLowerCase() === SEARCH_DEFAULT_MODEL;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function isSearchCapableProvider(provider) {
|
|
244
|
+
return SEARCH_CAPABLE_PROVIDERS.has(normalizeSearchProviderId(provider));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function normalizeSearchRouteConfig(routeLike, fallback = {}) {
|
|
248
|
+
const provider = normalizeSearchProviderId(routeLike?.provider || fallback.provider);
|
|
249
|
+
const model = clean(routeLike?.model || fallback.model);
|
|
250
|
+
if (!provider || !model) return null;
|
|
251
|
+
let effort = null;
|
|
252
|
+
try {
|
|
253
|
+
effort = normalizeEffortInput(routeLike?.effort ?? fallback.effort);
|
|
254
|
+
} catch {
|
|
255
|
+
effort = null;
|
|
256
|
+
}
|
|
257
|
+
const fast = routeLike?.fast ?? fallback.fast;
|
|
258
|
+
const toolType = clean(routeLike?.toolType || fallback.toolType);
|
|
259
|
+
return {
|
|
260
|
+
provider,
|
|
261
|
+
model,
|
|
262
|
+
...(effort ? { effort } : {}),
|
|
263
|
+
...(fast === true ? { fast: true } : {}),
|
|
264
|
+
...(toolType ? { toolType } : {}),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function normalizeWorkflowRoute(routeLike, fallback = {}) {
|
|
269
|
+
const provider = clean(routeLike?.provider) || clean(fallback.provider);
|
|
270
|
+
const model = clean(routeLike?.model) || clean(fallback.model);
|
|
271
|
+
if (!provider || !model) return null;
|
|
272
|
+
// Defensive: a workflow/agent route must carry a real model id. Reject values
|
|
273
|
+
// that are obviously free-form text (whitespace, prose) so a bad string can
|
|
274
|
+
// never be persisted as a preset/workflow route.
|
|
275
|
+
if (!isLikelyRawModelId(model)) return null;
|
|
276
|
+
const effort = normalizeEffortInput(routeLike?.effort ?? fallback.effort);
|
|
277
|
+
const fast = routeLike?.fast ?? fallback.fast;
|
|
278
|
+
return {
|
|
279
|
+
provider,
|
|
280
|
+
model,
|
|
281
|
+
...(effort ? { effort } : {}),
|
|
282
|
+
...(fast === true ? { fast: true } : {}),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function upsertWorkflowPreset(presets, slot, routeLike) {
|
|
287
|
+
const route = normalizeWorkflowRoute(routeLike);
|
|
288
|
+
if (!route) return presets;
|
|
289
|
+
const id = workflowPresetId(slot);
|
|
290
|
+
const preset = {
|
|
291
|
+
id,
|
|
292
|
+
name: workflowPresetName(slot),
|
|
293
|
+
type: 'agent',
|
|
294
|
+
provider: route.provider,
|
|
295
|
+
model: route.model,
|
|
296
|
+
...(route.effort ? { effort: route.effort } : {}),
|
|
297
|
+
...(route.fast === true ? { fast: true } : {}),
|
|
298
|
+
tools: 'full',
|
|
299
|
+
};
|
|
300
|
+
const next = (Array.isArray(presets) ? presets : []).filter((p) => clean(p?.id) !== id && clean(p?.name) !== preset.name);
|
|
301
|
+
next.push(preset);
|
|
302
|
+
return next;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Config-aware route resolvers need resolveDefaultProvider + findPreset from
|
|
306
|
+
// the runtime; created via this factory.
|
|
307
|
+
export function createWorkflowRouteHelpers({ resolveDefaultProvider, findPreset }) {
|
|
308
|
+
function summarizeWorkflowRoutes(config) {
|
|
309
|
+
const routes = config?.workflowRoutes && typeof config.workflowRoutes === 'object' ? config.workflowRoutes : {};
|
|
310
|
+
const fallbackProvider = resolveDefaultProvider(config);
|
|
311
|
+
const out = {};
|
|
312
|
+
for (const slot of WORKFLOW_ROUTE_SLOTS) {
|
|
313
|
+
const route = routes[slot];
|
|
314
|
+
// Read/interpret path: a route with a model but no provider falls back to
|
|
315
|
+
// config.defaultProvider (then DEFAULT_PROVIDER).
|
|
316
|
+
if (route?.model && (route?.provider || fallbackProvider)) {
|
|
317
|
+
out[slot] = normalizeWorkflowRoute(route, { provider: fallbackProvider });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return out;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function routeFromPreset(config, slotValue) {
|
|
324
|
+
// Maintenance slots now store a direct {provider, model} route. Accept that
|
|
325
|
+
// shape first; fall back to the legacy preset-NAME string lookup so configs
|
|
326
|
+
// written before the route migration still resolve.
|
|
327
|
+
if (slotValue && typeof slotValue === 'object' && !Array.isArray(slotValue)) {
|
|
328
|
+
const direct = normalizeWorkflowRoute(slotValue);
|
|
329
|
+
if (direct) return direct;
|
|
330
|
+
}
|
|
331
|
+
const preset = findPreset(config, slotValue);
|
|
332
|
+
return preset ? normalizeWorkflowRoute(preset) : null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function agentRouteFromConfig(config, agentId, _dataDir) {
|
|
336
|
+
const id = normalizeAgentId(agentId);
|
|
337
|
+
if (!id) return null;
|
|
338
|
+
// Read/interpret path: inject config.defaultProvider (then DEFAULT_PROVIDER)
|
|
339
|
+
// when a stored route omits its provider.
|
|
340
|
+
const fallback = { provider: resolveDefaultProvider(config) };
|
|
341
|
+
const explicit = normalizeWorkflowRoute(config?.agents?.[id], fallback)
|
|
342
|
+
|| (id === 'maintainer' ? normalizeWorkflowRoute(config?.agents?.maintenance, fallback) : null);
|
|
343
|
+
if (explicit) return explicit;
|
|
344
|
+
|
|
345
|
+
const agent = FIXED_AGENT_SLOTS.find((item) => item.id === id);
|
|
346
|
+
if (agent?.workflowSlot) {
|
|
347
|
+
const workflowRoute = normalizeWorkflowRoute(config?.workflowRoutes?.[agent.workflowSlot], fallback);
|
|
348
|
+
if (workflowRoute) return workflowRoute;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (id === 'explore') return routeFromPreset(config, config?.maintenance?.explore);
|
|
352
|
+
if (id === 'maintainer') return routeFromPreset(config, config?.maintenance?.memory);
|
|
353
|
+
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return { summarizeWorkflowRoutes, routeFromPreset, agentRouteFromConfig };
|
|
358
|
+
}
|