mixdog 0.9.3 → 0.9.5
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 +112 -38
- package/package.json +10 -3
- package/scripts/bench/lead-review-tasks-r3.json +20 -0
- package/scripts/bench/lead-review-tasks.json +20 -0
- package/scripts/bench/r4-mixed-tasks.json +20 -0
- package/scripts/bench/r5-orchestrated-task.json +7 -0
- package/scripts/bench/review-tasks.json +20 -0
- package/scripts/bench/round-codex.json +114 -0
- package/scripts/bench/round-mixdog-lead-r3.json +269 -0
- package/scripts/bench/round-mixdog-lead.json +269 -0
- package/scripts/bench/round-mixdog.json +126 -0
- package/scripts/bench/round-r10-bigsample.json +679 -0
- package/scripts/bench/round-r11-codexalign.json +257 -0
- package/scripts/bench/round-r13-clientmeta.json +464 -0
- package/scripts/bench/round-r14-betafeatures.json +466 -0
- package/scripts/bench/round-r15-fulldefault.json +462 -0
- package/scripts/bench/round-r16-sessionid.json +466 -0
- package/scripts/bench/round-r17-wirebytes.json +456 -0
- package/scripts/bench/round-r18-prewarm.json +468 -0
- package/scripts/bench/round-r19-clean.json +472 -0
- package/scripts/bench/round-r20-prewarm-clean.json +475 -0
- package/scripts/bench/round-r21-delta-retry.json +473 -0
- package/scripts/bench/round-r22-full-probe.json +693 -0
- package/scripts/bench/round-r23-itemprobe.json +701 -0
- package/scripts/bench/round-r24-shapefix.json +677 -0
- package/scripts/bench/round-r25-serial.json +464 -0
- package/scripts/bench/round-r26-parallel3.json +671 -0
- package/scripts/bench/round-r27-parallel10.json +894 -0
- package/scripts/bench/round-r28-parallel10-stagger.json +882 -0
- package/scripts/bench/round-r29-parallel10-stagger166.json +886 -0
- package/scripts/bench/round-r30-instid.json +253 -0
- package/scripts/bench/round-r31-upgradeprobe.json +256 -0
- package/scripts/bench/round-r32-vs-codex-lead.json +254 -0
- package/scripts/bench/round-r33-vs-codex-codex.json +115 -0
- package/scripts/bench/round-r34-orchestrated.json +120 -0
- package/scripts/bench/round-r35-orchestrated-codex.json +61 -0
- package/scripts/bench/round-r36-orchestrated-capped.json +128 -0
- package/scripts/bench/round-r4-codex.json +114 -0
- package/scripts/bench/round-r4-mixed.json +225 -0
- package/scripts/bench/round-r5-gpt-lead.json +259 -0
- package/scripts/bench/round-r6-codex.json +114 -0
- package/scripts/bench/round-r6-solo.json +257 -0
- package/scripts/bench/round-r7-full.json +254 -0
- package/scripts/bench/round-r8-fulldefault.json +255 -0
- package/scripts/bench-run.mjs +251 -32
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/internal-comms-bench.mjs +3 -4
- package/scripts/internal-comms-smoke.mjs +10 -9
- package/scripts/model-catalog-audit.mjs +209 -0
- package/scripts/model-list-sanitize-test.mjs +37 -0
- package/scripts/mouse-probe.mjs +45 -0
- package/scripts/output-style-bench.mjs +13 -6
- package/scripts/output-style-smoke.mjs +4 -4
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +76 -13
- package/scripts/recall-quality-cases.json +12 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +25 -65
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +4 -1
- package/src/agents/heavy-worker/AGENT.md +9 -8
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +2 -1
- package/src/agents/scheduler-task/AGENT.md +2 -3
- package/src/agents/webhook-handler/AGENT.md +2 -3
- package/src/agents/worker/AGENT.md +10 -7
- package/src/app.mjs +12 -1
- package/src/headless-role.mjs +7 -1
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +647 -2056
- package/src/output-styles/default.md +30 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +8 -6
- package/src/output-styles/simple.md +21 -7
- package/src/rules/agent/00-common.md +6 -3
- package/src/rules/agent/30-explorer.md +16 -5
- package/src/rules/lead/01-general.md +5 -5
- package/src/rules/lead/lead-brief.md +15 -0
- package/src/rules/lead/lead-tool.md +6 -15
- package/src/rules/shared/01-tool.md +17 -21
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +8 -3
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
- package/src/runtime/agent/orchestrator/config.mjs +69 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +62 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +81 -1281
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -3
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +43 -1013
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +105 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +356 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +40 -1143
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +740 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +349 -2131
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +143 -1002
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +229 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +465 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
- package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +275 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +278 -402
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +7 -4
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +166 -1087
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
- package/src/runtime/agent/orchestrator/stall-policy.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +35 -44
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -92
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +28 -265
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +0 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +57 -3
- package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +10 -122
- package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
- package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +0 -21
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -72
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
- package/src/runtime/channels/backends/discord-access.mjs +32 -0
- package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
- package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
- package/src/runtime/channels/backends/discord.mjs +27 -318
- package/src/runtime/channels/backends/telegram.mjs +8 -12
- package/src/runtime/channels/index.mjs +247 -701
- package/src/runtime/channels/lib/backend-dispatch.mjs +46 -0
- package/src/runtime/channels/lib/config.mjs +37 -149
- package/src/runtime/channels/lib/event-pipeline.mjs +22 -5
- package/src/runtime/channels/lib/event-queue.mjs +78 -13
- package/src/runtime/channels/lib/inbound-routing.mjs +74 -0
- package/src/runtime/channels/lib/interaction-workflows.mjs +5 -113
- package/src/runtime/channels/lib/output-forwarder.mjs +1 -1
- package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
- package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
- package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
- package/src/runtime/channels/lib/scheduler.mjs +27 -113
- package/src/runtime/channels/lib/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
- package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +313 -0
- package/src/runtime/channels/lib/webhook/log.mjs +42 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
- package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
- package/src/runtime/channels/lib/webhook.mjs +43 -616
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +210 -1948
- package/src/runtime/memory/lib/core-memory-store.mjs +5 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
- package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/ko-morph.mjs +195 -0
- package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
- package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +24 -842
- package/src/runtime/memory/lib/memory-embed.mjs +149 -0
- package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +69 -12
- package/src/runtime/memory/lib/memory-text-utils.mjs +46 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/query-handlers.mjs +802 -0
- package/src/runtime/memory/lib/recall-format.mjs +55 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
- package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
- package/src/runtime/memory/tool-defs.mjs +5 -13
- package/src/runtime/search/lib/http-fetch.mjs +274 -0
- package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
- package/src/runtime/search/lib/web-tools.mjs +24 -602
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/config.mjs +14 -4
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/markdown-frontmatter.mjs +19 -0
- package/src/runtime/shared/schedules-store.mjs +13 -3
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +308 -0
- package/src/runtime/shared/tool-result-summary.mjs +515 -0
- package/src/runtime/shared/tool-surface.mjs +80 -898
- package/src/runtime/shared/transcript-writer.mjs +23 -0
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +119 -2
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-recency.mjs +111 -0
- package/src/session-runtime/native-search.mjs +247 -0
- package/src/session-runtime/output-styles.mjs +11 -9
- package/src/session-runtime/prewarm.mjs +142 -0
- package/src/session-runtime/provider-models.mjs +278 -0
- package/src/session-runtime/provider-usage.mjs +120 -0
- package/src/session-runtime/quick-model-rows.mjs +205 -0
- package/src/session-runtime/quick-search-models.mjs +47 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/settings-api.mjs +352 -0
- package/src/session-runtime/tool-catalog.mjs +29 -29
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +1 -1
- package/src/standalone/agent-tool/helpers.mjs +237 -0
- package/src/standalone/agent-tool/notify.mjs +107 -0
- package/src/standalone/agent-tool/provider-init.mjs +143 -0
- package/src/standalone/agent-tool/render.mjs +152 -0
- package/src/standalone/agent-tool/tool-def.mjs +55 -0
- package/src/standalone/agent-tool.mjs +138 -669
- package/src/standalone/channel-admin.mjs +102 -90
- package/src/standalone/channel-worker.mjs +4 -7
- package/src/standalone/explore-tool.mjs +64 -14
- package/src/standalone/hook-bus/config.mjs +207 -0
- package/src/standalone/hook-bus/constants.mjs +90 -0
- package/src/standalone/hook-bus/handlers.mjs +481 -0
- package/src/standalone/hook-bus/payload.mjs +31 -0
- package/src/standalone/hook-bus/rules.mjs +77 -0
- package/src/standalone/hook-bus.mjs +77 -870
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +5 -1
- package/src/standalone/provider-admin.mjs +1 -16
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1059 -8110
- package/src/tui/app/app-format.mjs +213 -0
- package/src/tui/app/channel-pickers.mjs +508 -0
- package/src/tui/app/clipboard.mjs +67 -0
- package/src/tui/app/core-memory-picker.mjs +210 -0
- package/src/tui/app/extension-pickers.mjs +506 -0
- package/src/tui/app/input-parsers.mjs +193 -0
- package/src/tui/app/maintenance-pickers.mjs +356 -0
- package/src/tui/app/model-options.mjs +334 -0
- package/src/tui/app/model-picker.mjs +365 -0
- package/src/tui/app/onboarding-steps.mjs +400 -0
- package/src/tui/app/project-picker.mjs +247 -0
- package/src/tui/app/provider-setup-picker.mjs +580 -0
- package/src/tui/app/resume-picker.mjs +55 -0
- package/src/tui/app/route-pickers.mjs +419 -0
- package/src/tui/app/settings-picker.mjs +489 -0
- package/src/tui/app/slash-commands.mjs +101 -0
- package/src/tui/app/slash-dispatch.mjs +427 -0
- package/src/tui/app/text-layout.mjs +46 -0
- package/src/tui/app/theme-effort-pickers.mjs +154 -0
- package/src/tui/app/transcript-window.mjs +677 -0
- package/src/tui/app/use-mouse-input.mjs +460 -0
- package/src/tui/app/use-prompt-handlers.mjs +310 -0
- package/src/tui/app/use-transcript-scroll.mjs +512 -0
- package/src/tui/app/use-transcript-window.mjs +607 -0
- package/src/tui/components/ConfirmBar.jsx +10 -7
- package/src/tui/components/Picker.jsx +64 -15
- package/src/tui/components/PromptInput.jsx +33 -102
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +69 -15
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +52 -594
- package/src/tui/components/TranscriptItem.jsx +105 -0
- package/src/tui/components/UsagePanel.jsx +18 -4
- package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
- package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
- package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
- package/src/tui/components/tool-execution/text-format.mjs +161 -0
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +13553 -12384
- package/src/tui/engine/agent-job-feed.mjs +133 -0
- package/src/tui/engine/notification-plan.mjs +76 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-card-results.mjs +234 -0
- package/src/tui/engine/tool-result-status.mjs +135 -0
- package/src/tui/engine.mjs +170 -574
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +65 -1
- package/src/tui/input-editing.mjs +2 -2
- package/src/tui/markdown/format-token.mjs +4 -1
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/ui/statusline-agents.mjs +213 -0
- package/src/ui/statusline-format.mjs +146 -0
- package/src/ui/statusline-segments.mjs +148 -0
- package/src/ui/statusline.mjs +77 -501
- package/src/ui/tool-card.mjs +0 -1
- package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
- package/src/workflows/default/WORKFLOW.md +16 -18
- package/src/workflows/sequential/WORKFLOW.md +16 -18
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +112 -7
- package/vendor/ink/build/log-update.js +17 -3
- package/vendor/ink/build/wrap-text.js +125 -0
- package/scripts/_test-folder-dialog.mjs +0 -30
- package/scripts/fix-brief-fn.mjs +0 -35
- package/scripts/fix-format-tool-surface.mjs +0 -24
- package/scripts/fix-tool-exec-visible.mjs +0 -42
- package/scripts/patch-agent-brief.mjs +0 -48
- package/scripts/patch-app.mjs +0 -21
- package/scripts/patch-app2.mjs +0 -18
- package/scripts/patch-dist-brief.mjs +0 -96
- package/scripts/patch-tool-exec.mjs +0 -70
- package/src/examples/schedules/SCHEDULE.example.md +0 -32
- package/src/examples/webhooks/WEBHOOK.example.md +0 -40
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +0 -162
- package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
- package/src/runtime/channels/lib/holidays.mjs +0 -138
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- package/src/runtime/shared/task-notification-envelope.test.mjs +0 -107
- package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
- package/src/standalone/agent-task-status.test.mjs +0 -76
- package/src/tui/components/tool-output-format.test.mjs +0 -399
- package/src/tui/display-width.test.mjs +0 -35
- package/src/tui/engine-runtime-notification.test.mjs +0 -115
- package/src/tui/engine-tool-result-text.test.mjs +0 -75
- package/src/tui/input-editing.selection.test.mjs +0 -75
- package/src/tui/markdown/format-token.test.mjs +0 -354
- package/src/tui/markdown/render-ansi.test.mjs +0 -108
- package/src/tui/markdown/stream-fence.test.mjs +0 -26
- package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
- package/src/tui/paste-fix.test.mjs +0 -119
- package/src/tui/prompt-history-store.test.mjs +0 -52
- package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
- package/src/tui/transcript-tool-failures.test.mjs +0 -111
- package/src/ui/markdown.test.mjs +0 -70
- package/src/ui/statusline-context-label.test.mjs +0 -15
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
- package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// MCP config/status/connect glue, extracted from mixdog-session-runtime.mjs.
|
|
2
|
+
// Dependency-injected factory: all live state (config, currentCwd, connect
|
|
3
|
+
// generation/in-flight/failures) is threaded through accessors + a caller-owned
|
|
4
|
+
// `state` object so the facade's teardown/reconnect paths still observe it.
|
|
5
|
+
// Method behavior is byte-for-byte identical; only grouping changes.
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
import { clean } from './session-text.mjs';
|
|
8
|
+
import { readProjectMcpServers } from './plugin-mcp.mjs';
|
|
9
|
+
|
|
10
|
+
export function createMcpGlue({
|
|
11
|
+
mcpClient,
|
|
12
|
+
getConfig,
|
|
13
|
+
getCurrentCwd,
|
|
14
|
+
state,
|
|
15
|
+
}) {
|
|
16
|
+
function mcpTransportLabel(cfg = {}) {
|
|
17
|
+
if (cfg.autoDetect) return `autoDetect:${cfg.autoDetect}`;
|
|
18
|
+
try {
|
|
19
|
+
return mcpClient.resolveMcpTransportKind(cfg);
|
|
20
|
+
} catch {
|
|
21
|
+
return 'unknown';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Merge mixdog-config `agent.mcpServers` with project-local `.mcp.json`.
|
|
26
|
+
// On name collision the project-local `.mcp.json` entry WINS (Claude Code
|
|
27
|
+
// precedence: project > user config). `sources[name]` records each server's
|
|
28
|
+
// origin ('config' | 'project') for status reporting.
|
|
29
|
+
function resolveEffectiveMcpServers() {
|
|
30
|
+
const config = getConfig();
|
|
31
|
+
const configured = config?.mcpServers && typeof config.mcpServers === 'object'
|
|
32
|
+
? config.mcpServers
|
|
33
|
+
: {};
|
|
34
|
+
const project = readProjectMcpServers(getCurrentCwd());
|
|
35
|
+
const servers = { ...configured, ...project };
|
|
36
|
+
const sources = {};
|
|
37
|
+
for (const name of Object.keys(configured)) sources[name] = 'config';
|
|
38
|
+
for (const name of Object.keys(project)) sources[name] = 'project';
|
|
39
|
+
return { servers, sources };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function mcpStatus() {
|
|
43
|
+
const { servers: configured, sources } = resolveEffectiveMcpServers();
|
|
44
|
+
const connected = new Map((mcpClient.getMcpServerStatus?.() || []).map((row) => [row.name, row]));
|
|
45
|
+
const failures = new Map((state.mcpFailures || []).map((row) => [row.name, row]));
|
|
46
|
+
const servers = [];
|
|
47
|
+
for (const [name, cfg] of Object.entries(configured)) {
|
|
48
|
+
const live = connected.get(name);
|
|
49
|
+
const fail = failures.get(name);
|
|
50
|
+
servers.push({
|
|
51
|
+
name,
|
|
52
|
+
configured: true,
|
|
53
|
+
enabled: cfg?.enabled !== false,
|
|
54
|
+
connected: Boolean(live),
|
|
55
|
+
status: cfg?.enabled === false ? 'disabled' : live ? 'connected' : fail ? 'failed' : 'disconnected',
|
|
56
|
+
transport: mcpTransportLabel(cfg),
|
|
57
|
+
toolCount: live?.toolCount || 0,
|
|
58
|
+
tools: live?.tools || [],
|
|
59
|
+
error: fail?.msg || null,
|
|
60
|
+
source: sources[name] || 'config',
|
|
61
|
+
});
|
|
62
|
+
connected.delete(name);
|
|
63
|
+
}
|
|
64
|
+
for (const live of connected.values()) {
|
|
65
|
+
servers.push({ ...live, configured: false, status: 'connected' });
|
|
66
|
+
}
|
|
67
|
+
servers.sort((a, b) => String(a.name).localeCompare(String(b.name)));
|
|
68
|
+
return {
|
|
69
|
+
servers,
|
|
70
|
+
configuredCount: Object.keys(configured).length,
|
|
71
|
+
connectedCount: servers.filter((row) => row.connected).length,
|
|
72
|
+
failedCount: servers.filter((row) => row.status === 'failed').length,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function connectConfiguredMcp({ reset = false } = {}) {
|
|
77
|
+
// Serialize reconnects: boot connect, cwd-change reset, and rapid cwd
|
|
78
|
+
// switches must never interleave their disconnect/connect phases, or an
|
|
79
|
+
// older run finishing after a newer reset could re-add stale servers into
|
|
80
|
+
// the shared client registry. Approach: a generation token + a single
|
|
81
|
+
// in-flight promise. Each call bumps the generation, waits for any prior
|
|
82
|
+
// run to finish, then bails if a newer call has superseded it — leaving the
|
|
83
|
+
// latest requested effective-server-set in the registry.
|
|
84
|
+
const gen = ++state.mcpConnectGeneration;
|
|
85
|
+
if (state.mcpConnectInFlight) {
|
|
86
|
+
try { await state.mcpConnectInFlight; } catch { /* prior run's failures already captured */ }
|
|
87
|
+
}
|
|
88
|
+
if (gen !== state.mcpConnectGeneration) return mcpStatus();
|
|
89
|
+
const run = (async () => {
|
|
90
|
+
if (reset) await mcpClient.disconnectAll?.();
|
|
91
|
+
state.mcpFailures = [];
|
|
92
|
+
const { servers } = resolveEffectiveMcpServers();
|
|
93
|
+
if (Object.keys(servers).length === 0) return;
|
|
94
|
+
try {
|
|
95
|
+
await mcpClient.connectMcpServers(servers);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
state.mcpFailures = Array.isArray(error?.failures)
|
|
98
|
+
? error.failures
|
|
99
|
+
: [{ name: 'mcp', msg: error?.message || String(error) }];
|
|
100
|
+
}
|
|
101
|
+
})();
|
|
102
|
+
state.mcpConnectInFlight = run;
|
|
103
|
+
try {
|
|
104
|
+
await run;
|
|
105
|
+
} finally {
|
|
106
|
+
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
107
|
+
}
|
|
108
|
+
return mcpStatus();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function normalizeMcpServerInput(input = {}) {
|
|
112
|
+
const currentCwd = getCurrentCwd();
|
|
113
|
+
const name = clean(input.name).toLowerCase().replace(/[^a-z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
114
|
+
if (!name) throw new Error('MCP server name is required');
|
|
115
|
+
const coerceStringRecord = (value) => {
|
|
116
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
117
|
+
const out = {};
|
|
118
|
+
for (const [key, val] of Object.entries(value)) {
|
|
119
|
+
if (val === undefined || val === null) continue;
|
|
120
|
+
out[String(key)] = String(val);
|
|
121
|
+
}
|
|
122
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
123
|
+
};
|
|
124
|
+
const withOptionalHeaders = (config) => {
|
|
125
|
+
const headers = coerceStringRecord(input.headers);
|
|
126
|
+
if (headers) config.headers = headers;
|
|
127
|
+
return config;
|
|
128
|
+
};
|
|
129
|
+
const url = clean(input.url);
|
|
130
|
+
const type = clean(input.type).toLowerCase();
|
|
131
|
+
if (url) {
|
|
132
|
+
if (type === 'sse') {
|
|
133
|
+
if (!/^https?:\/\//i.test(url)) throw new Error('MCP URL must start with http:// or https://');
|
|
134
|
+
return { name, config: withOptionalHeaders({ type: 'sse', url }) };
|
|
135
|
+
}
|
|
136
|
+
if (type === 'ws') {
|
|
137
|
+
if (!/^(?:wss?|https?):\/\//i.test(url)) {
|
|
138
|
+
throw new Error('MCP WebSocket URL must start with ws://, wss://, http://, or https://');
|
|
139
|
+
}
|
|
140
|
+
return { name, config: withOptionalHeaders({ type: 'ws', url }) };
|
|
141
|
+
}
|
|
142
|
+
if (type === 'http' || type === 'streamable-http') {
|
|
143
|
+
if (!/^https?:\/\//i.test(url)) throw new Error('MCP URL must start with http:// or https://');
|
|
144
|
+
return { name, config: withOptionalHeaders({ type: 'http', url }) };
|
|
145
|
+
}
|
|
146
|
+
if (/^wss?:\/\//i.test(url)) {
|
|
147
|
+
return { name, config: withOptionalHeaders({ type: 'ws', url }) };
|
|
148
|
+
}
|
|
149
|
+
if (!/^https?:\/\//i.test(url)) throw new Error('MCP URL must start with http:// or https://');
|
|
150
|
+
return { name, config: withOptionalHeaders({ type: 'http', url }) };
|
|
151
|
+
}
|
|
152
|
+
const command = clean(input.command);
|
|
153
|
+
if (!command) throw new Error('MCP server command or URL is required');
|
|
154
|
+
const args = Array.isArray(input.args)
|
|
155
|
+
? input.args.map((v) => String(v)).filter(Boolean)
|
|
156
|
+
: clean(input.args).split(/\s+/).filter(Boolean);
|
|
157
|
+
const requestedCwd = clean(input.cwd);
|
|
158
|
+
const cwdForServer = requestedCwd ? resolve(currentCwd, requestedCwd) : currentCwd;
|
|
159
|
+
const root = resolve(currentCwd);
|
|
160
|
+
const resolvedCwd = resolve(cwdForServer);
|
|
161
|
+
if (resolvedCwd !== root && !resolvedCwd.startsWith(`${root}\\`) && !resolvedCwd.startsWith(`${root}/`)) {
|
|
162
|
+
throw new Error('MCP server cwd must stay under the current project');
|
|
163
|
+
}
|
|
164
|
+
const config = { type: 'stdio', command, args, cwd: resolvedCwd };
|
|
165
|
+
const env = coerceStringRecord(input.env);
|
|
166
|
+
if (env) config.env = env;
|
|
167
|
+
return { name, config };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
mcpTransportLabel,
|
|
172
|
+
resolveEffectiveMcpServers,
|
|
173
|
+
mcpStatus,
|
|
174
|
+
connectConfiguredMcp,
|
|
175
|
+
normalizeMcpServerInput,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Provider-model version parsing, recency comparison, sorting, and cache-row
|
|
2
|
+
// construction. Extracted from mixdog-session-runtime.mjs. Pure except for the
|
|
3
|
+
// injected route provider (for sort priority) and searchCapableFor predicate.
|
|
4
|
+
import { clean } from './session-text.mjs';
|
|
5
|
+
|
|
6
|
+
export function parsedProviderModelVersion(id) {
|
|
7
|
+
const text = clean(id).toLowerCase();
|
|
8
|
+
const claude = text.match(/^claude-[a-z]+-(\d+)(?:[-.](\d+))?/);
|
|
9
|
+
if (claude) return [Number(claude[1]) || 0, Number(claude[2]) || 0];
|
|
10
|
+
const compact = text.match(/(?:^|[-_])(?:o|gpt|grok|qwen|llama|mistral|gemma|phi|glm)(\d+)(?:\.(\d+))?(?:\.(\d{1,3}))?/);
|
|
11
|
+
if (compact) return compact.slice(1).filter((v) => v != null).map((v) => Number(v) || 0);
|
|
12
|
+
const generic = text.match(/(?:^|[-_v])(\d+)(?:\.(\d+))?(?:\.(\d{1,3}))?/);
|
|
13
|
+
return generic ? generic.slice(1).filter((v) => v != null).map((v) => Number(v) || 0) : [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function compareProviderModelVersion(a, b) {
|
|
17
|
+
const va = parsedProviderModelVersion(a.id || a.display || a.name);
|
|
18
|
+
const vb = parsedProviderModelVersion(b.id || b.display || b.name);
|
|
19
|
+
if (va.length === 0 && vb.length === 0) return 0;
|
|
20
|
+
if (va.length === 0) return 1;
|
|
21
|
+
if (vb.length === 0) return -1;
|
|
22
|
+
for (let i = 0; i < Math.max(va.length, vb.length); i += 1) {
|
|
23
|
+
const delta = (vb[i] || 0) - (va[i] || 0);
|
|
24
|
+
if (delta) return delta;
|
|
25
|
+
}
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function providerModelReleaseTime(model) {
|
|
30
|
+
if (model?.releaseDate) {
|
|
31
|
+
const t = Date.parse(model.releaseDate);
|
|
32
|
+
if (Number.isFinite(t)) return t;
|
|
33
|
+
}
|
|
34
|
+
const created = Number(model?.created);
|
|
35
|
+
if (Number.isFinite(created) && created > 0) {
|
|
36
|
+
return created < 1_000_000_000_000 ? created * 1000 : created;
|
|
37
|
+
}
|
|
38
|
+
const dated = clean(model?.id).match(/(?:^|-)(\d{4})(\d{2})(\d{2})(?:$|-)/);
|
|
39
|
+
return dated ? (Date.parse(`${dated[1]}-${dated[2]}-${dated[3]}`) || 0) : 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isClaudeProviderModel(model) {
|
|
43
|
+
return clean(model?.provider).toLowerCase().includes('anthropic')
|
|
44
|
+
&& /^claude-[a-z]+-/.test(clean(model?.id).toLowerCase());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function compareProviderModelRecency(a, b) {
|
|
48
|
+
if (isClaudeProviderModel(a) && isClaudeProviderModel(b)) {
|
|
49
|
+
if (a.latest !== b.latest) return a.latest ? -1 : 1;
|
|
50
|
+
const versionDelta = compareProviderModelVersion(a, b);
|
|
51
|
+
if (versionDelta) return versionDelta;
|
|
52
|
+
const ta = providerModelReleaseTime(a);
|
|
53
|
+
const tb = providerModelReleaseTime(b);
|
|
54
|
+
if (ta !== tb) return tb - ta;
|
|
55
|
+
return clean(a.display || a.id).localeCompare(clean(b.display || b.id));
|
|
56
|
+
}
|
|
57
|
+
const ta = providerModelReleaseTime(a);
|
|
58
|
+
const tb = providerModelReleaseTime(b);
|
|
59
|
+
if (ta !== tb) return tb - ta;
|
|
60
|
+
if (a.latest !== b.latest) return a.latest ? -1 : 1;
|
|
61
|
+
const versionDelta = compareProviderModelVersion(a, b);
|
|
62
|
+
if (versionDelta) return versionDelta;
|
|
63
|
+
return clean(a.display || a.id).localeCompare(clean(b.display || b.id));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function sortProviderModels(models, primaryProvider = '') {
|
|
67
|
+
return (models || []).sort((a, b) => {
|
|
68
|
+
const ar = a.provider === primaryProvider ? 0 : 1;
|
|
69
|
+
const br = b.provider === primaryProvider ? 0 : 1;
|
|
70
|
+
if (ar !== br) return ar - br;
|
|
71
|
+
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
72
|
+
return compareProviderModelRecency(a, b);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function isSelectableLlmModel(model) {
|
|
77
|
+
const id = clean(model?.id).toLowerCase();
|
|
78
|
+
const display = clean(model?.display || model?.name).toLowerCase();
|
|
79
|
+
const mode = clean(model?.mode).toLowerCase();
|
|
80
|
+
const text = `${id} ${display}`;
|
|
81
|
+
if (!id) return false;
|
|
82
|
+
if (mode && !['chat', 'completion', 'responses', 'messages'].includes(mode)) return false;
|
|
83
|
+
if (/(^|[-_\s])(image|images|video|videos|audio|tts|stt|speech|embed|embedding|embeddings|rerank|reranker|realtime|moderation|imagine)([-_\s]|$)/i.test(text)) return false;
|
|
84
|
+
if (/(^|[-_\s])(dall[-_\s]?e|sora|imagen)([-_\s]|$)/i.test(text)) return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function providerModelCacheRow(name, m, searchCapableFor) {
|
|
89
|
+
return {
|
|
90
|
+
id: m.id,
|
|
91
|
+
provider: name,
|
|
92
|
+
display: m.display || m.name || m.id,
|
|
93
|
+
created: typeof m.created === 'number' ? m.created : null,
|
|
94
|
+
releaseDate: m.releaseDate || null,
|
|
95
|
+
contextWindow: m.contextWindow,
|
|
96
|
+
outputTokens: m.outputTokens || null,
|
|
97
|
+
family: m.family || null,
|
|
98
|
+
tier: m.tier || null,
|
|
99
|
+
latest: m.latest === true,
|
|
100
|
+
description: m.description || '',
|
|
101
|
+
supportsVision: m.supportsVision === true,
|
|
102
|
+
supportsFunctionCalling: m.supportsFunctionCalling === true,
|
|
103
|
+
supportsWebSearch: searchCapableFor(name, m),
|
|
104
|
+
supportsPromptCaching: m.supportsPromptCaching === true,
|
|
105
|
+
supportsReasoning: m.supportsReasoning === true,
|
|
106
|
+
reasoningLevels: Array.isArray(m.reasoningLevels) ? m.reasoningLevels : undefined,
|
|
107
|
+
reasoningOptions: Array.isArray(m.reasoningOptions) ? m.reasoningOptions : [],
|
|
108
|
+
reasoningContentField: m.reasoningContentField || null,
|
|
109
|
+
mode: m.mode || null,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// Native (provider-hosted) web-search runtime, extracted from
|
|
2
|
+
// mixdog-session-runtime.mjs. Dependency-injected factory pattern: closes over
|
|
3
|
+
// route/searchRoute/config/reg/session accessors supplied by the facade.
|
|
4
|
+
import { clean } from './session-text.mjs';
|
|
5
|
+
|
|
6
|
+
export function createNativeSearch({
|
|
7
|
+
getRoute,
|
|
8
|
+
getSearchRoute,
|
|
9
|
+
setSearchRoute,
|
|
10
|
+
getConfig,
|
|
11
|
+
getSession,
|
|
12
|
+
getReg,
|
|
13
|
+
ensureFullConfig,
|
|
14
|
+
ensureProvidersReady,
|
|
15
|
+
ensureProviderEnabled,
|
|
16
|
+
normalizeSearchProviderId,
|
|
17
|
+
normalizeSearchRouteConfig,
|
|
18
|
+
isDefaultSearchRouteConfig,
|
|
19
|
+
isSearchCapableProvider,
|
|
20
|
+
searchCapableFor,
|
|
21
|
+
}) {
|
|
22
|
+
function normalizeSearchAllowedDomain(site) {
|
|
23
|
+
const raw = clean(site);
|
|
24
|
+
if (!raw) return '';
|
|
25
|
+
try {
|
|
26
|
+
return new URL(/^https?:\/\//i.test(raw) ? raw : `https://${raw}`).hostname.toLowerCase();
|
|
27
|
+
} catch {
|
|
28
|
+
return raw.replace(/^https?:\/\//i, '').split('/')[0].toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function nativeSearchUserLocation(locale) {
|
|
33
|
+
if (!locale || typeof locale !== 'object' || Array.isArray(locale)) return null;
|
|
34
|
+
const location = { type: 'approximate' };
|
|
35
|
+
for (const key of ['country', 'region', 'city', 'timezone']) {
|
|
36
|
+
const value = clean(locale[key]);
|
|
37
|
+
if (value) location[key] = value;
|
|
38
|
+
}
|
|
39
|
+
return Object.keys(location).length > 1 ? location : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function nativeSearchTool(args = {}, toolType = 'web_search', providerId = '') {
|
|
43
|
+
const providerName = normalizeSearchProviderId(providerId);
|
|
44
|
+
const domain = normalizeSearchAllowedDomain(args.site);
|
|
45
|
+
const type = clean(toolType) || 'web_search';
|
|
46
|
+
const location = nativeSearchUserLocation(args.locale);
|
|
47
|
+
if (providerName === 'gemini') {
|
|
48
|
+
return { type: type || 'google_search' };
|
|
49
|
+
}
|
|
50
|
+
if (providerName === 'anthropic' || providerName === 'anthropic-oauth') {
|
|
51
|
+
const tool = {
|
|
52
|
+
type: 'web_search_20250305',
|
|
53
|
+
name: 'web_search',
|
|
54
|
+
max_uses: Math.max(1, Math.min(10, Number(args.maxResults) || 5)),
|
|
55
|
+
};
|
|
56
|
+
if (domain) tool.allowed_domains = [domain];
|
|
57
|
+
if (location) tool.user_location = location;
|
|
58
|
+
return tool;
|
|
59
|
+
}
|
|
60
|
+
if (providerName === 'grok-oauth' || providerName === 'xai') {
|
|
61
|
+
const tool = { type };
|
|
62
|
+
if (domain) tool.filters = { allowed_domains: [domain] };
|
|
63
|
+
return tool;
|
|
64
|
+
}
|
|
65
|
+
const tool = {
|
|
66
|
+
type,
|
|
67
|
+
};
|
|
68
|
+
if (type === 'web_search') {
|
|
69
|
+
tool.search_context_size = clean(args.contextSize) || 'low';
|
|
70
|
+
if (domain) tool.filters = { allowed_domains: [domain] };
|
|
71
|
+
if (location) tool.user_location = location;
|
|
72
|
+
}
|
|
73
|
+
return tool;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function nativeSearchToolTypes(routeLike = {}) {
|
|
77
|
+
const envToolType = clean(process.env.MIXDOG_NATIVE_SEARCH_TOOL_TYPE);
|
|
78
|
+
if (envToolType) return [envToolType];
|
|
79
|
+
const configured = clean(routeLike.toolType);
|
|
80
|
+
if (configured) return [configured];
|
|
81
|
+
const providerName = normalizeSearchProviderId(routeLike.provider);
|
|
82
|
+
if (providerName === 'gemini') return ['google_search'];
|
|
83
|
+
if (providerName === 'anthropic' || providerName === 'anthropic-oauth') return ['web_search'];
|
|
84
|
+
if (providerName === 'grok-oauth' || providerName === 'xai') return ['web_search'];
|
|
85
|
+
return ['web_search', 'web_search_preview'];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function currentMainSearchModelMeta() {
|
|
89
|
+
const route = getRoute();
|
|
90
|
+
if (!route?.provider || !route?.model) return null;
|
|
91
|
+
return { ...route, id: route.model, display: route.model, name: route.model };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function nativeSearchRoutes() {
|
|
95
|
+
const route = getRoute();
|
|
96
|
+
const cfg = ensureFullConfig();
|
|
97
|
+
const searchRoute = normalizeSearchRouteConfig(cfg.searchRoute) || normalizeSearchRouteConfig(getSearchRoute());
|
|
98
|
+
setSearchRoute(searchRoute);
|
|
99
|
+
if (!searchRoute) return [];
|
|
100
|
+
if (isDefaultSearchRouteConfig(searchRoute)) {
|
|
101
|
+
const mainModel = currentMainSearchModelMeta();
|
|
102
|
+
if (!mainModel || !searchCapableFor(route.provider, mainModel)) return [];
|
|
103
|
+
return [{
|
|
104
|
+
key: `default\n${route.provider}\n${route.model}`,
|
|
105
|
+
provider: normalizeSearchProviderId(route.provider),
|
|
106
|
+
model: route.model,
|
|
107
|
+
source: 'default-search-route',
|
|
108
|
+
effort: route.effectiveEffort || route.effort || null,
|
|
109
|
+
fast: route.fast === true,
|
|
110
|
+
toolType: searchRoute.toolType || null,
|
|
111
|
+
}];
|
|
112
|
+
}
|
|
113
|
+
const providerName = normalizeSearchProviderId(searchRoute.provider);
|
|
114
|
+
if (!isSearchCapableProvider(providerName)) return [];
|
|
115
|
+
return [{
|
|
116
|
+
key: `${providerName}\n${searchRoute.model}`,
|
|
117
|
+
provider: providerName,
|
|
118
|
+
model: searchRoute.model,
|
|
119
|
+
source: 'search-route',
|
|
120
|
+
effort: searchRoute.effort || null,
|
|
121
|
+
fast: searchRoute.fast === true,
|
|
122
|
+
toolType: searchRoute.toolType || null,
|
|
123
|
+
}];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function nativeSearchMessages(searchArgs = {}) {
|
|
127
|
+
const prompt = searchArgs.prompt || '';
|
|
128
|
+
return [
|
|
129
|
+
{
|
|
130
|
+
role: 'system',
|
|
131
|
+
content: [
|
|
132
|
+
'You are Mixdog native web search.',
|
|
133
|
+
'Use the hosted web_search tool for current or external facts.',
|
|
134
|
+
'Answer concisely, cite source URLs, and do not request local tools or file edits.',
|
|
135
|
+
].join('\n'),
|
|
136
|
+
},
|
|
137
|
+
{ role: 'user', content: prompt },
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function flattenNativeSearchSources(result = {}) {
|
|
142
|
+
const out = [];
|
|
143
|
+
const add = (source, fallbackTitle = '') => {
|
|
144
|
+
if (!source || typeof source !== 'object') return;
|
|
145
|
+
const url = clean(source.url || source.uri || source.href || source.source_url);
|
|
146
|
+
if (!url) return;
|
|
147
|
+
out.push({
|
|
148
|
+
title: clean(source.title || source.query || source.name || fallbackTitle || url),
|
|
149
|
+
url,
|
|
150
|
+
snippet: clean(source.snippet || source.text || source.description),
|
|
151
|
+
source: source.source || 'native-web-search',
|
|
152
|
+
provider: source.provider || 'native-web-search',
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
for (const citation of Array.isArray(result.citations) ? result.citations : []) add(citation);
|
|
156
|
+
for (const call of Array.isArray(result.webSearchCalls) ? result.webSearchCalls : []) {
|
|
157
|
+
const action = call?.action || {};
|
|
158
|
+
for (const source of Array.isArray(action.sources) ? action.sources : []) add(source, action.query || '');
|
|
159
|
+
if (action.url) add({ url: action.url, title: action.query || '' });
|
|
160
|
+
for (const url of Array.isArray(action.urls) ? action.urls : []) add({ url, title: action.query || '' });
|
|
161
|
+
}
|
|
162
|
+
const seen = new Set();
|
|
163
|
+
return out.filter((item) => {
|
|
164
|
+
const key = item.url || `${item.title}\n${item.snippet}`;
|
|
165
|
+
if (!key || seen.has(key)) return false;
|
|
166
|
+
seen.add(key);
|
|
167
|
+
return true;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function runNativeWebSearch(searchArgs = {}, { signal } = {}) {
|
|
172
|
+
const route = getRoute();
|
|
173
|
+
const session = getSession();
|
|
174
|
+
const reg = getReg();
|
|
175
|
+
const candidates = nativeSearchRoutes();
|
|
176
|
+
if (!candidates.length) {
|
|
177
|
+
if (isDefaultSearchRouteConfig(getSearchRoute())) {
|
|
178
|
+
throw new Error(`default search route requires the current main model to support native web search (${route?.provider || 'unknown'}/${route?.model || 'unknown'})`);
|
|
179
|
+
}
|
|
180
|
+
throw new Error('search route is not configured; open /search to choose a search provider/model');
|
|
181
|
+
}
|
|
182
|
+
const errors = [];
|
|
183
|
+
for (const candidate of candidates) {
|
|
184
|
+
for (const toolType of nativeSearchToolTypes(candidate)) {
|
|
185
|
+
try {
|
|
186
|
+
// Read config lazily: nativeSearchRoutes() above may have run
|
|
187
|
+
// ensureFullConfig() and replaced the facade config with the
|
|
188
|
+
// secret-bearing one — an early snapshot would miss those secrets.
|
|
189
|
+
await ensureProvidersReady(ensureProviderEnabled(getConfig(), candidate.provider));
|
|
190
|
+
const providerImpl = reg.getProvider(candidate.provider);
|
|
191
|
+
if (!providerImpl || typeof providerImpl.send !== 'function') {
|
|
192
|
+
throw new Error(`provider "${candidate.provider}" is not ready`);
|
|
193
|
+
}
|
|
194
|
+
const model = candidate.model;
|
|
195
|
+
const searchTool = nativeSearchTool(searchArgs, toolType, candidate.provider);
|
|
196
|
+
const startedAt = Date.now();
|
|
197
|
+
const result = await providerImpl.send(
|
|
198
|
+
nativeSearchMessages(searchArgs),
|
|
199
|
+
model,
|
|
200
|
+
undefined,
|
|
201
|
+
{
|
|
202
|
+
signal,
|
|
203
|
+
role: 'web-search',
|
|
204
|
+
sessionId: `${session?.id || 'search'}:native-search:${Date.now().toString(36)}`,
|
|
205
|
+
sourceType: 'native-search',
|
|
206
|
+
sourceName: 'search',
|
|
207
|
+
nativeTools: [searchTool],
|
|
208
|
+
nativeInclude: candidate.provider === 'openai' || candidate.provider === 'openai-oauth'
|
|
209
|
+
? ['web_search_call.action.sources']
|
|
210
|
+
: [],
|
|
211
|
+
toolChoice: candidate.provider === 'gemini' ? 'auto' : 'required',
|
|
212
|
+
...(candidate.effort ? { effort: candidate.effort } : {}),
|
|
213
|
+
fast: candidate.fast === true,
|
|
214
|
+
onStageChange: () => {},
|
|
215
|
+
onStreamDelta: () => {},
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
const sources = flattenNativeSearchSources(result);
|
|
219
|
+
return {
|
|
220
|
+
content: String(result?.content || '').trim(),
|
|
221
|
+
provider: candidate.provider,
|
|
222
|
+
model: result?.model || candidate.model || null,
|
|
223
|
+
usage: result?.usage || null,
|
|
224
|
+
citations: sources,
|
|
225
|
+
webSearchCalls: result?.webSearchCalls || [],
|
|
226
|
+
durationMs: Date.now() - startedAt,
|
|
227
|
+
};
|
|
228
|
+
} catch (err) {
|
|
229
|
+
errors.push(`${candidate.provider}${candidate.model ? `/${candidate.model}` : ''}/${toolType}: ${err?.message || String(err)}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
throw new Error(`native web search failed: ${errors.join(' | ')}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
normalizeSearchAllowedDomain,
|
|
238
|
+
nativeSearchUserLocation,
|
|
239
|
+
nativeSearchTool,
|
|
240
|
+
nativeSearchToolTypes,
|
|
241
|
+
currentMainSearchModelMeta,
|
|
242
|
+
nativeSearchRoutes,
|
|
243
|
+
nativeSearchMessages,
|
|
244
|
+
flattenNativeSearchSources,
|
|
245
|
+
runNativeWebSearch,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -5,18 +5,20 @@ import { readFileSync, readdirSync } from 'node:fs';
|
|
|
5
5
|
import { clean } from './session-text.mjs';
|
|
6
6
|
import { readJsonSafe } from './fs-utils.mjs';
|
|
7
7
|
|
|
8
|
-
const OUTPUT_STYLE_ORDER = ['default', 'simple', 'minimal', '
|
|
8
|
+
const OUTPUT_STYLE_ORDER = ['default', 'simple', 'minimal', 'extreme-minimal'];
|
|
9
9
|
const OUTPUT_STYLE_ALIASES = new Map([
|
|
10
10
|
['compact', 'default'],
|
|
11
11
|
['normal', 'default'],
|
|
12
|
-
['extreme', 'minimal'],
|
|
13
|
-
['extremesimple', 'minimal'],
|
|
14
|
-
['extreme-simple', 'minimal'],
|
|
15
|
-
['extreme_simple', 'minimal'],
|
|
16
|
-
['
|
|
17
|
-
['
|
|
18
|
-
['
|
|
19
|
-
['
|
|
12
|
+
['extreme', 'extreme-minimal'],
|
|
13
|
+
['extremesimple', 'extreme-minimal'],
|
|
14
|
+
['extreme-simple', 'extreme-minimal'],
|
|
15
|
+
['extreme_simple', 'extreme-minimal'],
|
|
16
|
+
['extrememinimal', 'extreme-minimal'],
|
|
17
|
+
['extreme_minimal', 'extreme-minimal'],
|
|
18
|
+
['mono', 'extreme-minimal'],
|
|
19
|
+
['oneline', 'extreme-minimal'],
|
|
20
|
+
['one-line', 'extreme-minimal'],
|
|
21
|
+
['one_line', 'extreme-minimal'],
|
|
20
22
|
]);
|
|
21
23
|
|
|
22
24
|
export function normalizeOutputStyleId(value) {
|