mixdog 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -23
- package/package.json +33 -27
- package/scripts/_test-folder-dialog.mjs +30 -0
- package/scripts/agent-parallel-smoke.mjs +388 -0
- package/scripts/agent-tag-reuse-smoke.mjs +183 -0
- package/scripts/background-task-meta-smoke.mjs +38 -0
- package/scripts/boot-smoke.mjs +52 -9
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/compact-active-turn-test.mjs +68 -0
- package/scripts/compact-smoke.mjs +859 -129
- package/scripts/compact-trigger-migration-smoke.mjs +187 -0
- package/scripts/fix-brief-fn.mjs +35 -0
- package/scripts/fix-format-tool-surface.mjs +24 -0
- package/scripts/fix-tool-exec-visible.mjs +42 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/hook-bus-test.mjs +330 -0
- package/scripts/lead-workflow-smoke.mjs +33 -39
- package/scripts/live-worker-smoke.mjs +43 -37
- package/scripts/llm-trace-summary.mjs +315 -0
- package/scripts/memory-meta-concurrency-test.mjs +20 -0
- package/scripts/output-style-smoke.mjs +56 -15
- package/scripts/parent-abort-link-test.mjs +44 -0
- package/scripts/patch-agent-brief.mjs +48 -0
- package/scripts/patch-app.mjs +21 -0
- package/scripts/patch-app2.mjs +18 -0
- package/scripts/patch-dist-brief.mjs +96 -0
- package/scripts/patch-tool-exec.mjs +70 -0
- package/scripts/pretool-ask-runtime-test.mjs +54 -0
- package/scripts/provider-toolcall-test.mjs +376 -0
- package/scripts/reactive-compact-persist-smoke.mjs +124 -0
- package/scripts/sanitize-tool-pairs-test.mjs +260 -0
- package/scripts/session-context-bench.mjs +344 -0
- package/scripts/session-ingest-smoke.mjs +177 -0
- package/scripts/set-effort-config-test.mjs +41 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -0
- package/scripts/smoke-runtime-negative.sh +97 -0
- package/scripts/smoke.mjs +25 -0
- package/scripts/tool-result-hook-test.mjs +48 -0
- package/scripts/tool-smoke.mjs +1223 -95
- package/scripts/toolcall-args-test.mjs +150 -0
- package/scripts/tui-background-failure-smoke.mjs +73 -0
- package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
- package/src/agents/debugger/AGENT.md +8 -0
- package/src/agents/explore/AGENT.md +4 -0
- package/src/agents/heavy-worker/AGENT.md +9 -3
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +8 -0
- package/src/agents/scheduler-task/AGENT.md +12 -0
- package/src/agents/scheduler-task/agent.json +6 -0
- package/src/agents/webhook-handler/AGENT.md +12 -0
- package/src/agents/webhook-handler/agent.json +6 -0
- package/src/agents/worker/AGENT.md +9 -3
- package/src/app.mjs +77 -3
- package/src/defaults/hidden-roles.json +17 -12
- package/src/headless-role.mjs +117 -0
- package/src/help.mjs +30 -0
- package/src/hooks/lib/permission-evaluator.cjs +11 -475
- package/src/lib/keychain-cjs.cjs +9 -1
- package/src/lib/mixdog-debug.cjs +0 -7
- package/src/lib/rules-builder.cjs +240 -96
- package/src/lib/text-utils.cjs +1 -1
- package/src/mixdog-session-runtime.mjs +2325 -450
- package/src/output-styles/default.md +12 -28
- package/src/output-styles/extreme-simple.md +9 -6
- package/src/output-styles/simple.md +22 -9
- package/src/repl.mjs +118 -59
- package/src/rules/agent/00-common.md +15 -0
- package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
- package/src/rules/agent/30-explorer.md +22 -0
- package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
- package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
- package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
- package/src/rules/lead/01-general.md +9 -5
- package/src/rules/lead/04-workflow.md +51 -12
- package/src/rules/lead/lead-tool.md +6 -0
- package/src/rules/shared/01-tool.md +12 -1
- package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
- package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
- package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
- package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
- package/src/runtime/agent/orchestrator/config.mjs +174 -55
- package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
- package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
- package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +377 -243
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +146 -93
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +221 -70
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +477 -147
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -496
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +31 -11
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
- package/src/runtime/agent/orchestrator/session/loop.mjs +851 -674
- package/src/runtime/agent/orchestrator/session/manager.mjs +1593 -466
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +291 -46
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
- package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +34 -7
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +9 -9
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
- package/src/runtime/channels/index.mjs +152 -24
- package/src/runtime/channels/lib/scheduler.mjs +18 -14
- package/src/runtime/channels/lib/session-discovery.mjs +3 -2
- package/src/runtime/channels/lib/tool-format.mjs +0 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +3 -2
- package/src/runtime/channels/lib/webhook.mjs +1 -1
- package/src/runtime/channels/tool-defs.mjs +29 -29
- package/src/runtime/memory/index.mjs +635 -107
- package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
- package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
- package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
- package/src/runtime/memory/lib/memory-cycle1.mjs +38 -17
- package/src/runtime/memory/lib/memory-cycle2.mjs +6 -7
- package/src/runtime/memory/lib/memory-cycle3.mjs +4 -4
- package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
- package/src/runtime/memory/lib/memory.mjs +88 -9
- package/src/runtime/memory/lib/model-profile.mjs +1 -1
- package/src/runtime/memory/lib/pg/adapter.mjs +15 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +37 -3
- package/src/runtime/memory/lib/session-ingest.mjs +194 -0
- package/src/runtime/memory/lib/trace-store.mjs +96 -51
- package/src/runtime/memory/tool-defs.mjs +46 -37
- package/src/runtime/search/index.mjs +102 -466
- package/src/runtime/search/lib/web-tools.mjs +45 -25
- package/src/runtime/search/tool-defs.mjs +16 -23
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +4 -3
- package/src/runtime/shared/background-tasks.mjs +122 -11
- package/src/runtime/shared/child-spawn-gate.mjs +145 -0
- package/src/runtime/shared/config.mjs +7 -4
- package/src/runtime/shared/err-text.mjs +131 -4
- package/src/runtime/shared/llm/cost.mjs +2 -2
- package/src/runtime/shared/llm/http-agent.mjs +23 -7
- package/src/runtime/shared/llm/index.mjs +34 -11
- package/src/runtime/shared/llm/usage-log.mjs +4 -4
- package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
- package/src/runtime/shared/singleton-owner.mjs +104 -0
- package/src/runtime/shared/tool-execution-contract.mjs +199 -20
- package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
- package/src/runtime/shared/tool-surface.mjs +624 -98
- package/src/runtime/shared/user-data-guard.mjs +0 -2
- package/src/standalone/agent-task-status.mjs +203 -0
- package/src/standalone/agent-task-status.test.mjs +76 -0
- package/src/standalone/agent-tool.mjs +1913 -0
- package/src/standalone/channel-worker.mjs +370 -14
- package/src/standalone/explore-tool.mjs +165 -70
- package/src/standalone/folder-dialog.mjs +314 -0
- package/src/standalone/hook-bus.mjs +898 -22
- package/src/standalone/memory-runtime-proxy.mjs +320 -0
- package/src/standalone/projects.mjs +226 -0
- package/src/standalone/provider-admin.mjs +41 -24
- package/src/standalone/seeds.mjs +2 -69
- package/src/standalone/usage-dashboard.mjs +96 -8
- package/src/tui/App.jsx +4798 -2153
- package/src/tui/components/AnsiText.jsx +39 -28
- package/src/tui/components/ContextPanel.jsx +87 -29
- package/src/tui/components/Markdown.jsx +43 -77
- package/src/tui/components/MarkdownTable.jsx +9 -184
- package/src/tui/components/Message.jsx +28 -11
- package/src/tui/components/Picker.jsx +95 -56
- package/src/tui/components/PromptInput.jsx +367 -239
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +27 -21
- package/src/tui/components/Spinner.jsx +67 -38
- package/src/tui/components/StatusLine.jsx +606 -38
- package/src/tui/components/TextEntryPanel.jsx +128 -9
- package/src/tui/components/ToolExecution.jsx +617 -368
- package/src/tui/components/TurnDone.jsx +3 -3
- package/src/tui/components/UsagePanel.jsx +3 -5
- package/src/tui/components/tool-output-format.mjs +365 -0
- package/src/tui/components/tool-output-format.test.mjs +220 -0
- package/src/tui/dist/index.mjs +8915 -2418
- package/src/tui/engine-runtime-notification.test.mjs +115 -0
- package/src/tui/engine-tool-result-text.test.mjs +75 -0
- package/src/tui/engine.mjs +1455 -279
- package/src/tui/figures.mjs +21 -40
- package/src/tui/index.jsx +75 -31
- package/src/tui/input-editing.mjs +25 -0
- package/src/tui/markdown/format-token.mjs +511 -68
- package/src/tui/markdown/format-token.test.mjs +216 -0
- package/src/tui/markdown/render-ansi.mjs +94 -0
- package/src/tui/markdown/render-ansi.test.mjs +108 -0
- package/src/tui/markdown/stream-fence.mjs +34 -0
- package/src/tui/markdown/stream-fence.test.mjs +26 -0
- package/src/tui/markdown/table-layout.mjs +250 -0
- package/src/tui/paste-attachments.mjs +0 -7
- package/src/tui/spinner-verbs.mjs +1 -2
- package/src/tui/statusline-ansi-bridge.mjs +172 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
- package/src/tui/theme.mjs +746 -24
- package/src/tui/time-format.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +67 -0
- package/src/tui/transcript-tool-failures.test.mjs +111 -0
- package/src/ui/ansi.mjs +1 -2
- package/src/ui/markdown.mjs +85 -26
- package/src/ui/markdown.test.mjs +70 -0
- package/src/ui/model-display.mjs +121 -0
- package/src/ui/session-stats.mjs +44 -0
- package/src/ui/statusline-context-label.test.mjs +15 -0
- package/src/ui/statusline.mjs +386 -178
- package/src/ui/tool-card.mjs +3 -16
- package/src/vendor/statusline/bin/statusline-lib.mjs +8 -4
- package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
- package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
- package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +12 -5
- package/src/workflows/default/workflow.json +0 -1
- package/src/workflows/solo/WORKFLOW.md +15 -0
- package/src/workflows/solo/workflow.json +7 -0
- package/vendor/ink/build/output.js +6 -1
- package/src/agents/scheduler-task.md +0 -3
- package/src/agents/web-researcher/AGENT.md +0 -3
- package/src/agents/web-researcher/agent.json +0 -6
- package/src/agents/webhook-handler.md +0 -3
- package/src/rules/bridge/00-common.md +0 -5
- package/src/rules/bridge/30-explorer.md +0 -4
- package/src/rules/lead/00-tool-lead.md +0 -5
- package/src/rules/shared/00-language.md +0 -3
- package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
- package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
- package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
- package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
- package/src/standalone/bridge-tool.mjs +0 -1414
- package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { resolvePluginData } from '../../shared/plugin-paths.mjs';
|
|
2
2
|
import { readSection, updateSection, getAgentApiKey, AGENT_PROVIDER_ENV } from '../../shared/config.mjs';
|
|
3
|
-
import { OPENAI_COMPAT_PRESETS } from './providers/openai-compat.mjs';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { OPENAI_COMPAT_PRESETS } from './providers/openai-compat-presets.mjs';
|
|
4
|
+
import {
|
|
5
|
+
hasAnthropicOAuthCredentials,
|
|
6
|
+
hasOpenAIOAuthCredentials,
|
|
7
|
+
hasGrokOAuthCredentials,
|
|
8
|
+
} from './providers/oauth-credential-probes.mjs';
|
|
7
9
|
|
|
8
10
|
// Thin wrapper around resolvePluginData so callers in this orchestrator tree
|
|
9
11
|
// can import a single helper without reaching into shared/.
|
|
@@ -17,7 +19,7 @@ export function getPluginData() {
|
|
|
17
19
|
// llm/index.mjs and setup-server.mjs so UI/runtime cannot drift from config.
|
|
18
20
|
//
|
|
19
21
|
// Every hidden maintenance slot carries a CONCRETE preset here, so
|
|
20
|
-
// resolvePresetName() (
|
|
22
|
+
// resolvePresetName() (agent-dispatch) always resolves a model directly from
|
|
21
23
|
// `maint[slot]` — no shared `defaultPreset` fallback is needed or used.
|
|
22
24
|
// Memory cycles + Lead helper fan-out (explore/cycle1/cycle2/cycle3) and
|
|
23
25
|
// entry-driven dispatch (scheduler/webhook) all default to `haiku`. The three
|
|
@@ -28,13 +30,6 @@ export function getPluginData() {
|
|
|
28
30
|
// scheduler/webhook still let a per-entry config.json model win first (the
|
|
29
31
|
// caller passes it explicitly via opts.preset); the haiku default below only
|
|
30
32
|
// applies when an entry omits its own model.
|
|
31
|
-
export const DEFAULT_MAINTENANCE = Object.freeze({
|
|
32
|
-
explore: 'haiku',
|
|
33
|
-
memory: 'haiku',
|
|
34
|
-
scheduler: 'haiku',
|
|
35
|
-
webhook: 'haiku',
|
|
36
|
-
});
|
|
37
|
-
|
|
38
33
|
// Slots surfaced as tunable rows in the Maintenance Setup panel. This is the
|
|
39
34
|
// UI / allow-list view (GET cleanup + POST validation) and is intentionally a
|
|
40
35
|
// SUBSET of DEFAULT_MAINTENANCE: scheduler/webhook carry a per-entry model and
|
|
@@ -42,6 +37,56 @@ export const DEFAULT_MAINTENANCE = Object.freeze({
|
|
|
42
37
|
// an entry omits its own model.
|
|
43
38
|
export const MAINTENANCE_SLOTS = Object.freeze(['explore', 'memory']);
|
|
44
39
|
|
|
40
|
+
// --- User profile (statusline /profile) -------------------------------------
|
|
41
|
+
// Supported response languages for the /profile picker. `system` is the default
|
|
42
|
+
// sentinel: it leaves the language unset so the model follows the user's locale
|
|
43
|
+
// / written language (no forced "Always respond in X" injection). Each entry is
|
|
44
|
+
// { id, label, prompt } — `prompt` is the human language name the prompt-side
|
|
45
|
+
// wiring uses for "Always respond in <prompt>." Keep `system` first.
|
|
46
|
+
export const PROFILE_LANGUAGES = Object.freeze([
|
|
47
|
+
{ id: 'system', label: 'System (locale)', prompt: null },
|
|
48
|
+
{ id: 'en', label: 'English', prompt: 'English' },
|
|
49
|
+
{ id: 'ko', label: '한국어', prompt: 'Korean (한국어)' },
|
|
50
|
+
{ id: 'ja', label: '日本語', prompt: 'Japanese (日本語)' },
|
|
51
|
+
{ id: 'zh-Hans', label: '中文(简体)', prompt: 'Simplified Chinese (简体中文)' },
|
|
52
|
+
{ id: 'zh-Hant', label: '中文(繁體)', prompt: 'Traditional Chinese (繁體中文)' },
|
|
53
|
+
{ id: 'es', label: 'Español', prompt: 'Spanish (Español)' },
|
|
54
|
+
{ id: 'fr', label: 'Français', prompt: 'French (Français)' },
|
|
55
|
+
{ id: 'de', label: 'Deutsch', prompt: 'German (Deutsch)' },
|
|
56
|
+
{ id: 'pt', label: 'Português', prompt: 'Portuguese (Português)' },
|
|
57
|
+
{ id: 'ru', label: 'Русский', prompt: 'Russian (Русский)' },
|
|
58
|
+
{ id: 'it', label: 'Italiano', prompt: 'Italian (Italiano)' },
|
|
59
|
+
{ id: 'vi', label: 'Tiếng Việt', prompt: 'Vietnamese (Tiếng Việt)' },
|
|
60
|
+
{ id: 'th', label: 'ภาษาไทย', prompt: 'Thai (ภาษาไทย)' },
|
|
61
|
+
{ id: 'id', label: 'Bahasa Indonesia', prompt: 'Indonesian (Bahasa Indonesia)' },
|
|
62
|
+
{ id: 'hi', label: 'हिन्दी', prompt: 'Hindi (हिन्दी)' },
|
|
63
|
+
{ id: 'ar', label: 'العربية', prompt: 'Arabic (العربية)' },
|
|
64
|
+
{ id: 'tr', label: 'Türkçe', prompt: 'Turkish (Türkçe)' },
|
|
65
|
+
{ id: 'pl', label: 'Polski', prompt: 'Polish (Polski)' },
|
|
66
|
+
{ id: 'nl', label: 'Nederlands', prompt: 'Dutch (Nederlands)' },
|
|
67
|
+
{ id: 'uk', label: 'Українська', prompt: 'Ukrainian (Українська)' },
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
const PROFILE_LANGUAGE_IDS = new Set(PROFILE_LANGUAGES.map((lang) => lang.id));
|
|
71
|
+
const PROFILE_TITLE_MAX = 64;
|
|
72
|
+
|
|
73
|
+
// Resolve a stored profile (or raw config fragment) into a stable shape:
|
|
74
|
+
// { title: string, language: <valid id> }
|
|
75
|
+
// Unknown language ids fall back to 'system'; titles are trimmed/capped.
|
|
76
|
+
export function normalizeProfileConfig(value = {}) {
|
|
77
|
+
const raw = value && typeof value === 'object' ? value : {};
|
|
78
|
+
const title = String(raw.title ?? raw.name ?? '').trim().slice(0, PROFILE_TITLE_MAX);
|
|
79
|
+
const requested = String(raw.language ?? raw.lang ?? 'system').trim();
|
|
80
|
+
const language = PROFILE_LANGUAGE_IDS.has(requested) ? requested : 'system';
|
|
81
|
+
return { title, language };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Look up the catalog entry for a stored language id (defaults to 'system').
|
|
85
|
+
export function profileLanguageEntry(languageId) {
|
|
86
|
+
const id = String(languageId || 'system');
|
|
87
|
+
return PROFILE_LANGUAGES.find((lang) => lang.id === id) || PROFILE_LANGUAGES[0];
|
|
88
|
+
}
|
|
89
|
+
|
|
45
90
|
// Map short Anthropic family labels to the full model ids used by the API.
|
|
46
91
|
// Honors ANTHROPIC_DEFAULT_{OPUS|SONNET|HAIKU}_MODEL env overrides.
|
|
47
92
|
const ANTHROPIC_FAMILY_MODEL = Object.freeze({
|
|
@@ -57,14 +102,37 @@ function resolveAnthropicFamilyModel(family) {
|
|
|
57
102
|
return ANTHROPIC_FAMILY_MODEL[key] || null;
|
|
58
103
|
}
|
|
59
104
|
|
|
105
|
+
// Canonical maintenance defaults. Single source of truth — imported by
|
|
106
|
+
// llm/index.mjs and setup-server.mjs so UI/runtime cannot drift from config.
|
|
107
|
+
//
|
|
108
|
+
// Each maintenance slot stores its model route DIRECTLY ({provider, model}) —
|
|
109
|
+
// parity with `agents.<role>`. The old shape stored a preset NAME string (e.g.
|
|
110
|
+
// "haiku") that had to be looked up in the config.presets array; that
|
|
111
|
+
// indirection is the legacy path. agent-dispatch.resolveMaintenanceRoute still
|
|
112
|
+
// accepts a legacy name string for backward compatibility, but new configs and
|
|
113
|
+
// these defaults use the direct route. loadConfig() migrates any stored string
|
|
114
|
+
// slot to a route on read (see migrateMaintenanceRoutes). The cycle1/2/3 memory
|
|
115
|
+
// agents share ONE `memory` route via the `maintKey: 'memory'` override on
|
|
116
|
+
// their hidden-role entries.
|
|
117
|
+
const _HAIKU_ROUTE = Object.freeze({
|
|
118
|
+
provider: 'anthropic-oauth',
|
|
119
|
+
model: resolveAnthropicFamilyModel('haiku'),
|
|
120
|
+
});
|
|
121
|
+
export const DEFAULT_MAINTENANCE = Object.freeze({
|
|
122
|
+
explore: { ..._HAIKU_ROUTE },
|
|
123
|
+
memory: { ..._HAIKU_ROUTE },
|
|
124
|
+
scheduler: { ..._HAIKU_ROUTE },
|
|
125
|
+
webhook: { ..._HAIKU_ROUTE },
|
|
126
|
+
});
|
|
127
|
+
|
|
60
128
|
// Seed presets keyed by preset.name so workflow/maintenance references stay
|
|
61
129
|
// consistent with the resolve-by-name lookup in presetKey().
|
|
62
130
|
export const DEFAULT_PRESETS = Object.freeze([
|
|
63
|
-
Object.freeze({ id: 'haiku', name: 'HAIKU', type: '
|
|
64
|
-
Object.freeze({ id: 'sonnet-mid', name: 'SONNET MID', type: '
|
|
65
|
-
Object.freeze({ id: 'sonnet-high', name: 'SONNET HIGH', type: '
|
|
66
|
-
Object.freeze({ id: 'opus-mid', name: 'OPUS MID', type: '
|
|
67
|
-
Object.freeze({ id: 'opus-high', name: 'OPUS HIGH', type: '
|
|
131
|
+
Object.freeze({ id: 'haiku', name: 'HAIKU', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('haiku'), tools: 'full' }),
|
|
132
|
+
Object.freeze({ id: 'sonnet-mid', name: 'SONNET MID', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('sonnet'), effort: 'medium', tools: 'full' }),
|
|
133
|
+
Object.freeze({ id: 'sonnet-high', name: 'SONNET HIGH', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('sonnet'), effort: 'high', tools: 'full' }),
|
|
134
|
+
Object.freeze({ id: 'opus-mid', name: 'OPUS MID', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('opus'), effort: 'medium', tools: 'full' }),
|
|
135
|
+
Object.freeze({ id: 'opus-high', name: 'OPUS HIGH', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('opus'), effort: 'high', tools: 'full' }),
|
|
68
136
|
]);
|
|
69
137
|
function buildDefaultConfig(options = {}) {
|
|
70
138
|
const detectCredentials = options.detectCredentials !== false;
|
|
@@ -77,18 +145,16 @@ function buildDefaultConfig(options = {}) {
|
|
|
77
145
|
apiKey: apiKey || undefined,
|
|
78
146
|
};
|
|
79
147
|
}
|
|
80
|
-
// OAuth provider detection
|
|
81
|
-
//
|
|
82
|
-
// single source of truth. WebSocket transport is on by default —
|
|
148
|
+
// OAuth provider detection uses lightweight credential probes so config
|
|
149
|
+
// load does not import provider runtimes or SDKs. WebSocket transport is on by default —
|
|
83
150
|
// measured ~96% cross-session cache hit with delta payloads. Users who
|
|
84
151
|
// need to force SSE (e.g. a corporate proxy blocking WSS) can set
|
|
85
152
|
// `websocket: false` in mixdog-config.json (agent.providers.openai-oauth).
|
|
86
153
|
providers['openai-oauth'] = { enabled: detectCredentials ? hasOpenAIOAuthCredentials() : false, websocket: true };
|
|
87
154
|
providers['anthropic-oauth'] = { enabled: detectCredentials ? hasAnthropicOAuthCredentials() : false };
|
|
88
|
-
// Grok
|
|
155
|
+
// Grok OAuth ("Grok Build"). Like the other OAuth entries it is not
|
|
89
156
|
// stored in mixdog-config.json — enabled at runtime from the presence of
|
|
90
|
-
//
|
|
91
|
-
// hasGrokOAuthCredentials().
|
|
157
|
+
// Mixdog-owned credentials.
|
|
92
158
|
providers['grok-oauth'] = { enabled: detectCredentials ? hasGrokOAuthCredentials() : false };
|
|
93
159
|
// Local providers — opt-in via setup UI after HTTP ping confirms server is running
|
|
94
160
|
providers.ollama = { enabled: false, baseURL: 'http://localhost:11434/v1' };
|
|
@@ -100,10 +166,65 @@ function hasKeys(value) {
|
|
|
100
166
|
return !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
101
167
|
}
|
|
102
168
|
|
|
169
|
+
function normalizeSearchRoute(route) {
|
|
170
|
+
if (!route || typeof route !== 'object' || Array.isArray(route))
|
|
171
|
+
return null;
|
|
172
|
+
const provider = normalizeAgentProviderId(route.provider);
|
|
173
|
+
const model = String(route.model || '').trim();
|
|
174
|
+
if (!provider || !model)
|
|
175
|
+
return null;
|
|
176
|
+
const out = { provider, model };
|
|
177
|
+
const effort = String(route.effort || '').trim();
|
|
178
|
+
if (effort)
|
|
179
|
+
out.effort = effort;
|
|
180
|
+
if (route.fast === true)
|
|
181
|
+
out.fast = true;
|
|
182
|
+
const toolType = String(route.toolType || '').trim();
|
|
183
|
+
if (toolType)
|
|
184
|
+
out.toolType = toolType;
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Migrate stored maintenance slots from the legacy preset-NAME string shape to
|
|
189
|
+
// the direct {provider, model} route shape. A slot value that is already a
|
|
190
|
+
// route object is normalized (provider/model/effort/fast only); a string value
|
|
191
|
+
// is resolved against the config.presets array (the legacy lookup) and rewritten
|
|
192
|
+
// to a route. Unresolvable strings are dropped so the DEFAULT_MAINTENANCE route
|
|
193
|
+
// fills the slot. `presets` is the normalized preset array for legacy lookup.
|
|
194
|
+
function migrateMaintenanceRoutes(rawMaint, presets) {
|
|
195
|
+
const out = {};
|
|
196
|
+
const list = Array.isArray(presets) ? presets : [];
|
|
197
|
+
for (const [slot, value] of Object.entries(rawMaint || {})) {
|
|
198
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
199
|
+
const provider = normalizeAgentProviderId(value.provider);
|
|
200
|
+
const model = String(value.model || '').trim();
|
|
201
|
+
if (provider && model) {
|
|
202
|
+
const route = { provider, model };
|
|
203
|
+
const effort = String(value.effort || '').trim();
|
|
204
|
+
if (effort) route.effort = effort;
|
|
205
|
+
if (value.fast === true) route.fast = true;
|
|
206
|
+
out[slot] = route;
|
|
207
|
+
}
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const name = String(value || '').trim();
|
|
211
|
+
if (!name) continue;
|
|
212
|
+
const preset = list.find(p => p && (p.id === name || p.name === name));
|
|
213
|
+
if (preset && preset.provider && preset.model) {
|
|
214
|
+
const route = { provider: preset.provider, model: preset.model };
|
|
215
|
+
if (preset.effort) route.effort = preset.effort;
|
|
216
|
+
if (preset.fast === true) route.fast = true;
|
|
217
|
+
out[slot] = route;
|
|
218
|
+
}
|
|
219
|
+
// Unresolvable legacy name → dropped; DEFAULT_MAINTENANCE route fills it.
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
|
|
103
224
|
// Persist the agent section. `build` receives the section value read INSIDE
|
|
104
225
|
// the file lock (current on-disk state) and returns the full replacement.
|
|
105
226
|
// Building from `current` rather than a snapshot taken before the lock keeps
|
|
106
|
-
// the whole-section save linearizable: a concurrent writer (each
|
|
227
|
+
// the whole-section save linearizable: a concurrent writer (each host-agent
|
|
107
228
|
// session runs its own server under MIXDOG_MULTI_INSTANCE) that lands between
|
|
108
229
|
// our read and write is rebased onto, not silently clobbered (lost-update).
|
|
109
230
|
function persistAgentConfig(build) {
|
|
@@ -169,7 +290,7 @@ export function loadConfig(options = {}) {
|
|
|
169
290
|
migratedMaintenance = true;
|
|
170
291
|
}
|
|
171
292
|
// Self-ref guard: mcpServers.mixdog / mcpServers["trib-plugin"]
|
|
172
|
-
// would self-spawn through the in-process tool
|
|
293
|
+
// would self-spawn through the in-process tool adapter. Strip on
|
|
173
294
|
// ingress so user-edited configs cannot brick the agent boot.
|
|
174
295
|
const mcpServers = (raw.mcpServers && typeof raw.mcpServers === 'object') ? { ...raw.mcpServers } : {};
|
|
175
296
|
if (mcpServers['mixdog'] || mcpServers['trib-plugin']) {
|
|
@@ -239,22 +360,28 @@ export function loadConfig(options = {}) {
|
|
|
239
360
|
.filter(p => p.id !== 'workflow-search');
|
|
240
361
|
const workflowRoutes = raw.workflowRoutes && typeof raw.workflowRoutes === 'object' ? { ...raw.workflowRoutes } : {};
|
|
241
362
|
delete workflowRoutes.search;
|
|
363
|
+
// Migrate legacy preset-name maintenance slots to direct routes,
|
|
364
|
+
// then overlay onto the route-shaped defaults.
|
|
365
|
+
const migratedMaint = migrateMaintenanceRoutes(rawMaint, normalizedPresets);
|
|
242
366
|
return {
|
|
243
367
|
providers: mergedProviders,
|
|
244
368
|
mcpServers,
|
|
245
369
|
presets: normalizedPresets,
|
|
246
370
|
default: raw.default || null,
|
|
247
|
-
maintenance: { ...DEFAULT_MAINTENANCE, ...
|
|
371
|
+
maintenance: { ...DEFAULT_MAINTENANCE, ...migratedMaint },
|
|
248
372
|
workflowRoutes,
|
|
373
|
+
searchRoute: normalizeSearchRoute(raw.searchRoute),
|
|
249
374
|
fastModels: raw.fastModels && typeof raw.fastModels === 'object' ? raw.fastModels : {},
|
|
250
375
|
modelSettings: raw.modelSettings && typeof raw.modelSettings === 'object' ? raw.modelSettings : {},
|
|
251
376
|
onboarding: raw.onboarding && typeof raw.onboarding === 'object' ? raw.onboarding : {},
|
|
252
377
|
agents: raw.agents && typeof raw.agents === 'object' ? raw.agents : {},
|
|
253
378
|
workflow: raw.workflow && typeof raw.workflow === 'object' ? { active: String(raw.workflow.active || 'default') } : { active: 'default' },
|
|
254
379
|
agentMaintenance: { enabled: true, interval: '1h', ...raw.agentMaintenance },
|
|
380
|
+
profile: normalizeProfileConfig(raw.profile),
|
|
255
381
|
autoClear: { enabled: true, idleMs: 60 * 60 * 1000, ...raw.autoClear },
|
|
382
|
+
compaction: raw.compaction && typeof raw.compaction === 'object' ? { ...raw.compaction } : {},
|
|
256
383
|
trajectory: { enabled: true, ...raw.trajectory },
|
|
257
|
-
|
|
384
|
+
runtime: raw.runtime && typeof raw.runtime === 'object' ? raw.runtime : {},
|
|
258
385
|
shell: raw.shell && typeof raw.shell === 'object' ? raw.shell : {},
|
|
259
386
|
};
|
|
260
387
|
}
|
|
@@ -268,15 +395,18 @@ export function loadConfig(options = {}) {
|
|
|
268
395
|
default: null,
|
|
269
396
|
maintenance: { ...DEFAULT_MAINTENANCE },
|
|
270
397
|
workflowRoutes: {},
|
|
398
|
+
searchRoute: null,
|
|
271
399
|
fastModels: {},
|
|
272
400
|
modelSettings: {},
|
|
273
401
|
onboarding: {},
|
|
274
402
|
agents: {},
|
|
275
403
|
workflow: { active: 'default' },
|
|
276
404
|
agentMaintenance: { enabled: true, interval: '1h' },
|
|
405
|
+
profile: normalizeProfileConfig(null),
|
|
277
406
|
autoClear: { enabled: true, idleMs: 60 * 60 * 1000 },
|
|
407
|
+
compaction: {},
|
|
278
408
|
trajectory: { enabled: true },
|
|
279
|
-
|
|
409
|
+
runtime: {},
|
|
280
410
|
shell: {},
|
|
281
411
|
};
|
|
282
412
|
}
|
|
@@ -293,8 +423,8 @@ export function loadConfig(options = {}) {
|
|
|
293
423
|
* maintenance/...) are replaced from the passed snapshot (last-writer-wins);
|
|
294
424
|
* only unmanaged keys are rebased on the in-lock current. Safe only for a
|
|
295
425
|
* caller holding a fresh full config. For a single-field change, patch in-lock
|
|
296
|
-
* via persistAgentConfig((current) => ({ ...current, <field> }))
|
|
297
|
-
*
|
|
426
|
+
* via persistAgentConfig((current) => ({ ...current, <field> })) so a
|
|
427
|
+
* concurrent instance's edits are not reverted.
|
|
298
428
|
*/
|
|
299
429
|
export function saveConfig(config) {
|
|
300
430
|
// Strip ephemeral defaults from providers but preserve any unknown
|
|
@@ -339,20 +469,23 @@ export function saveConfig(config) {
|
|
|
339
469
|
default: config.default || null,
|
|
340
470
|
maintenance: config.maintenance || {},
|
|
341
471
|
workflowRoutes,
|
|
472
|
+
searchRoute: normalizeSearchRoute(config.searchRoute),
|
|
342
473
|
fastModels: config.fastModels || {},
|
|
343
474
|
modelSettings: config.modelSettings || {},
|
|
344
475
|
onboarding: config.onboarding || {},
|
|
345
476
|
agents: config.agents || {},
|
|
346
477
|
workflow: config.workflow || { active: 'default' },
|
|
347
478
|
agentMaintenance: config.agentMaintenance || {},
|
|
479
|
+
profile: normalizeProfileConfig(config.profile),
|
|
348
480
|
autoClear: config.autoClear || {},
|
|
481
|
+
compaction: config.compaction || {},
|
|
349
482
|
trajectory: config.trajectory || {},
|
|
350
|
-
|
|
483
|
+
runtime: config.runtime || {},
|
|
351
484
|
shell: config.shell || {},
|
|
352
485
|
}));
|
|
353
486
|
}
|
|
354
487
|
// --- Preset helpers ---
|
|
355
|
-
// preset shape: { id, name, type: '
|
|
488
|
+
// preset shape: { id, name, type: 'agent', provider, model, effort?, fast?, tools? }
|
|
356
489
|
const AGENT_PROVIDER_ALIASES = Object.freeze({
|
|
357
490
|
'openai-api': 'openai',
|
|
358
491
|
'gemini-api': 'gemini',
|
|
@@ -377,7 +510,7 @@ function normalizePreset(preset) {
|
|
|
377
510
|
const model = String(preset.model || '').trim();
|
|
378
511
|
const provider = normalizeAgentProviderId(preset.provider);
|
|
379
512
|
if (!name || !model || !provider) return null;
|
|
380
|
-
const out = { id, name, type: '
|
|
513
|
+
const out = { id, name, type: 'agent', provider, model };
|
|
381
514
|
if (preset.effort)
|
|
382
515
|
out.effort = String(preset.effort).trim();
|
|
383
516
|
if (preset.fast === true && FAST_CAPABLE_PRESET_PROVIDERS.has(provider))
|
|
@@ -413,34 +546,20 @@ export function listPresets(config) {
|
|
|
413
546
|
// (both cache shards are identical there), while swapping the model itself
|
|
414
547
|
// legitimately needs a fresh session (cache shard is model-specific). Two
|
|
415
548
|
// presets mapping to the same (provider, model) therefore collapse into
|
|
416
|
-
// one
|
|
549
|
+
// one Agent session, so opus-mid / opus-max no longer fragment the pool.
|
|
417
550
|
//
|
|
418
|
-
//
|
|
419
|
-
// other lane:
|
|
551
|
+
// agent lane: "agent:<agentId>:<provider>:<model>" — per Sub role
|
|
552
|
+
// other lane: "agent:<provider>:<model>" — shared utility
|
|
420
553
|
export function resolveRuntimeSpec(preset, ctx) {
|
|
421
|
-
const lane = ctx.lane || '
|
|
554
|
+
const lane = ctx.lane || 'agent';
|
|
422
555
|
const provider = String(preset?.provider || '').trim() || 'unknown';
|
|
423
556
|
const model = String(preset?.model || '').trim() || '_';
|
|
424
557
|
let scopeKey;
|
|
425
|
-
if (lane === '
|
|
426
|
-
if (!ctx.agentId) throw new Error('
|
|
427
|
-
scopeKey = `
|
|
558
|
+
if (lane === 'agent') {
|
|
559
|
+
if (!ctx.agentId) throw new Error('agent lane requires agentId');
|
|
560
|
+
scopeKey = `agent:${ctx.agentId}:${provider}:${model}`;
|
|
428
561
|
} else {
|
|
429
|
-
scopeKey = `
|
|
562
|
+
scopeKey = `agent:${provider}:${model}`;
|
|
430
563
|
}
|
|
431
564
|
return { lane, scopeKey, reuse: true, preset };
|
|
432
565
|
}
|
|
433
|
-
|
|
434
|
-
export function setDefaultPreset(config, key) {
|
|
435
|
-
const preset = getPreset(config, key);
|
|
436
|
-
if (!preset)
|
|
437
|
-
throw new Error(`preset "${key}" not found`);
|
|
438
|
-
const nextDefault = presetKey(preset);
|
|
439
|
-
// Patch only `default` under the file lock. saveConfig(config) would
|
|
440
|
-
// rewrite the whole agent section from this possibly-stale snapshot and
|
|
441
|
-
// could revert a concurrent instance's preset edits; an in-lock single
|
|
442
|
-
// field patch cannot.
|
|
443
|
-
persistAgentConfig((current) => ({ ...current, default: nextDefault }));
|
|
444
|
-
config.default = nextDefault;
|
|
445
|
-
return preset;
|
|
446
|
-
}
|