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
package/scripts/tool-smoke.mjs
CHANGED
|
@@ -3,15 +3,16 @@ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'nod
|
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { __renderToolSearchForTest, compactToolSearchDescription, defaultDeferredToolNames, SKILL_TOOL, TOOL_SEARCH_TOOL } from '../src/mixdog-session-runtime.mjs';
|
|
6
|
+
import { __applyStandaloneToolDefaultsForTest, __renderToolSearchForTest, compactToolSearchDescription, defaultDeferredToolNames, SKILL_TOOL, TOOL_SEARCH_TOOL } from '../src/mixdog-session-runtime.mjs';
|
|
7
7
|
import { buildExplorerPrompt, EXPLORE_TOOL, MAX_FANOUT_QUERIES, normalizeExploreQueries } from '../src/standalone/explore-tool.mjs';
|
|
8
8
|
import { AGENT_TOOL, createStandaloneAgent } from '../src/standalone/agent-tool.mjs';
|
|
9
9
|
import { parseHeadlessRoleCommand } from '../src/app.mjs';
|
|
10
10
|
import { buildHeadlessSpawnArgs } from '../src/headless-role.mjs';
|
|
11
11
|
import { createStandaloneChannelWorker } from '../src/standalone/channel-worker.mjs';
|
|
12
12
|
import { OpenAIOAuthProvider, buildRequestBody, sendViaHttpSse } from '../src/runtime/agent/orchestrator/providers/openai-oauth.mjs';
|
|
13
|
+
import { _test as _anthropicOAuthTest } from '../src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs';
|
|
13
14
|
import { _logicalResponseItemMatch, _resolveOpenAiPromptCacheRatePolicy } from '../src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs';
|
|
14
|
-
import { _mergePendingMessageEntries, closeSession, createSession, drainPendingMessages, enqueuePendingMessage, resumeSession } from '../src/runtime/agent/orchestrator/session/manager.mjs';
|
|
15
|
+
import { _mergePendingMessageEntries, applyAskTerminalUsageTotals, closeSession, createSession, drainPendingMessages, enqueuePendingMessage, resumeSession } from '../src/runtime/agent/orchestrator/session/manager.mjs';
|
|
15
16
|
import {
|
|
16
17
|
contentHasImage,
|
|
17
18
|
normalizeContentForAnthropic,
|
|
@@ -28,7 +29,8 @@ import {
|
|
|
28
29
|
shouldRecordObservedForProvider,
|
|
29
30
|
} from '../src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs';
|
|
30
31
|
import { executeBuiltinTool } from '../src/runtime/agent/orchestrator/tools/builtin.mjs';
|
|
31
|
-
import { validateBuiltinArgs } from '../src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs';
|
|
32
|
+
import { applyGrepContextLeadPolicy, GREP_CONTEXT_MAX, validateBuiltinArgs } from '../src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs';
|
|
33
|
+
import { normaliseReadLineWindowArgs } from '../src/runtime/agent/orchestrator/tools/builtin/read-args.mjs';
|
|
32
34
|
import { BUILTIN_TOOLS } from '../src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs';
|
|
33
35
|
import { runResultCacheInFlight } from '../src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs';
|
|
34
36
|
import { executeCodeGraphTool } from '../src/runtime/agent/orchestrator/tools/code-graph.mjs';
|
|
@@ -44,7 +46,7 @@ import { composeSystemPrompt } from '../src/runtime/agent/orchestrator/context/c
|
|
|
44
46
|
import { setInternalToolsProvider } from '../src/runtime/agent/orchestrator/internal-tools.mjs';
|
|
45
47
|
import { prepareAgentSession } from '../src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs';
|
|
46
48
|
import { resolveHiddenRoleSchemaAllowedTools } from '../src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs';
|
|
47
|
-
import {
|
|
49
|
+
import { getHiddenAgent, resolveAgentSessionPermission } from '../src/runtime/agent/orchestrator/internal-agents.mjs';
|
|
48
50
|
|
|
49
51
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
50
52
|
|
|
@@ -63,6 +65,27 @@ function assertOk(name, result, pattern = null) {
|
|
|
63
65
|
return text;
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
{
|
|
69
|
+
const session = { provider: 'openai-oauth' };
|
|
70
|
+
applyAskTerminalUsageTotals(session, {
|
|
71
|
+
usage: { inputTokens: 100_000, outputTokens: 10, cachedTokens: 98_000, cacheWriteTokens: 0 },
|
|
72
|
+
});
|
|
73
|
+
assert(session.lastInputTokens === 100_000, `inclusive last input should retain provider total: ${JSON.stringify(session)}`);
|
|
74
|
+
assert(session.lastUncachedInputTokens === 2_000, `inclusive last uncached input should subtract cache reads: ${JSON.stringify(session)}`);
|
|
75
|
+
assert(session.totalUncachedInputTokens === 2_000, `inclusive total uncached input should be tracked: ${JSON.stringify(session)}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
{
|
|
79
|
+
const session = { provider: 'anthropic-oauth' };
|
|
80
|
+
applyAskTerminalUsageTotals(session, {
|
|
81
|
+
usage: { inputTokens: 2_000, outputTokens: 10, cachedTokens: 90_000, cacheWriteTokens: 8_000 },
|
|
82
|
+
});
|
|
83
|
+
assert(session.lastInputTokens === 2_000, `additive last input should retain provider input field: ${JSON.stringify(session)}`);
|
|
84
|
+
assert(session.lastUncachedInputTokens === 10_000, `additive uncached input should include cache writes: ${JSON.stringify(session)}`);
|
|
85
|
+
assert(session.lastContextTokens === 100_000, `additive context should include input+cache read+cache write: ${JSON.stringify(session)}`);
|
|
86
|
+
assert(session.totalUncachedInputTokens === 10_000, `additive total uncached input should include cache writes: ${JSON.stringify(session)}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
66
89
|
{
|
|
67
90
|
const sid = `tool-smoke-rich-pending-${process.pid}-${Date.now()}`.replace(/[^A-Za-z0-9_-]/g, '_');
|
|
68
91
|
const richContent = [
|
|
@@ -193,7 +216,9 @@ function assertOk(name, result, pattern = null) {
|
|
|
193
216
|
{
|
|
194
217
|
const publicStrategy = resolveCacheStrategy('worker');
|
|
195
218
|
assert(publicStrategy.tools === 'none', `Anthropic tools must not spend a cache_control BP: ${JSON.stringify(publicStrategy)}`);
|
|
196
|
-
|
|
219
|
+
// BP1~3 stay 1h (pool-stable prefix); volatile message tail is 5m for all
|
|
220
|
+
// sessions — see resolveCacheStrategy docs (trace p99 gap ≈ 4.5min).
|
|
221
|
+
assert(publicStrategy.system === '1h' && publicStrategy.tier3 === '1h' && publicStrategy.messages === '5m', `public cache tiers changed unexpectedly: ${JSON.stringify(publicStrategy)}`);
|
|
197
222
|
assert(cacheCapabilityForProvider('anthropic-oauth') === 'explicit-breakpoint', 'Anthropic OAuth should remain explicit-breakpoint');
|
|
198
223
|
assert(cacheCapabilityForProvider('openai-oauth') === 'key-prefix', 'OpenAI OAuth should remain key-prefix');
|
|
199
224
|
assert(cacheCapabilityForProvider('xai') === 'key-prefix', 'xAI should remain key-prefix');
|
|
@@ -355,6 +380,7 @@ const grepOut = await executeBuiltinTool('grep', {
|
|
|
355
380
|
pattern: ['standalone mixdog CLI/TUI coding agent', 'smoke passed'],
|
|
356
381
|
path: 'scripts',
|
|
357
382
|
glob: '*.mjs',
|
|
383
|
+
output_mode: 'content_with_context',
|
|
358
384
|
head_limit: 10,
|
|
359
385
|
}, root);
|
|
360
386
|
assertOk('grep', grepOut, /smoke\.mjs/);
|
|
@@ -390,8 +416,8 @@ assertOk('find', findOut, /scripts[\\/]tool-smoke\.mjs/i);
|
|
|
390
416
|
|
|
391
417
|
const readOut = await executeBuiltinTool('read', {
|
|
392
418
|
path: 'scripts/smoke.mjs',
|
|
393
|
-
|
|
394
|
-
|
|
419
|
+
offset: 0,
|
|
420
|
+
limit: 4,
|
|
395
421
|
}, root);
|
|
396
422
|
assertOk('read', readOut, /spawnSync/);
|
|
397
423
|
|
|
@@ -402,12 +428,71 @@ if (!/^Error[\s:[]/.test(String(readDirOut)) || !/read expects a file/i.test(Str
|
|
|
402
428
|
throw new Error(`read directory must be classified as Error:\n${readDirOut}`);
|
|
403
429
|
}
|
|
404
430
|
|
|
431
|
+
const readRegionBatchOut = await executeBuiltinTool('read', {
|
|
432
|
+
path: [
|
|
433
|
+
{ path: 'scripts/smoke.mjs', offset: 0, limit: 2 },
|
|
434
|
+
{ path: 'scripts/smoke.mjs', offset: 2, limit: 2 },
|
|
435
|
+
],
|
|
436
|
+
}, root);
|
|
437
|
+
if (!/^read 2\b/m.test(String(readRegionBatchOut))
|
|
438
|
+
|| (String(readRegionBatchOut).match(/scripts\/smoke\.mjs \[full\] \[ok\]/g) || []).length < 2
|
|
439
|
+
|| !/1→import \{ spawnSync \}/.test(String(readRegionBatchOut))
|
|
440
|
+
|| !/3→import \{ fileURLToPath \}/.test(String(readRegionBatchOut))
|
|
441
|
+
|| !/pass offset:2 to continue/.test(String(readRegionBatchOut))
|
|
442
|
+
|| !/pass offset:4 to continue/.test(String(readRegionBatchOut))) {
|
|
443
|
+
throw new Error(`read region batch must preserve both requested spans:\n${readRegionBatchOut}`);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const readStringifiedRegionArgs = {
|
|
447
|
+
path: JSON.stringify([{ path: 'scripts/smoke.mjs', offset: 0, limit: 2 }]),
|
|
448
|
+
};
|
|
449
|
+
const readStringifiedRegionErr = validateBuiltinArgs('read', readStringifiedRegionArgs);
|
|
450
|
+
if (readStringifiedRegionErr || !Array.isArray(readStringifiedRegionArgs.path)) {
|
|
451
|
+
throw new Error(`read guard must losslessly coerce stringified path arrays: err=${readStringifiedRegionErr} args=${JSON.stringify(readStringifiedRegionArgs)}`);
|
|
452
|
+
}
|
|
453
|
+
const readStringifiedRegionOut = await executeBuiltinTool('read', {
|
|
454
|
+
path: JSON.stringify([{ path: 'scripts/smoke.mjs', offset: 0, limit: 2 }]),
|
|
455
|
+
}, root);
|
|
456
|
+
if (!/^read 1\b/m.test(String(readStringifiedRegionOut)) || !/scripts\/smoke\.mjs \[full\] \[ok\]/.test(String(readStringifiedRegionOut)) || !/1→import \{ spawnSync \}/.test(String(readStringifiedRegionOut))) {
|
|
457
|
+
throw new Error(`read stringified region batch must execute after guard coercion:\n${readStringifiedRegionOut}`);
|
|
458
|
+
}
|
|
459
|
+
const readStringifiedLineArgs = {
|
|
460
|
+
path: JSON.stringify([{ path: 'scripts/smoke.mjs', line: 10, context: 2 }]),
|
|
461
|
+
};
|
|
462
|
+
const readStringifiedLineErr = validateBuiltinArgs('read', readStringifiedLineArgs);
|
|
463
|
+
if (readStringifiedLineErr || readStringifiedLineArgs.path[0].offset !== 7 || readStringifiedLineArgs.path[0].limit !== 5) {
|
|
464
|
+
throw new Error(`read guard must losslessly convert legacy line/context inside stringified arrays to offset/limit: err=${readStringifiedLineErr} args=${JSON.stringify(readStringifiedLineArgs)}`);
|
|
465
|
+
}
|
|
466
|
+
|
|
405
467
|
const graphOut = await executeCodeGraphTool('code_graph', {
|
|
406
468
|
mode: 'symbols',
|
|
407
469
|
file: 'scripts/smoke.mjs',
|
|
408
470
|
}, root);
|
|
409
471
|
assertOk('code_graph', graphOut, /binding|spawnSync|symbol/i);
|
|
410
472
|
|
|
473
|
+
const graphSymbolBatchOut = await executeCodeGraphTool('code_graph', {
|
|
474
|
+
mode: 'symbol_search',
|
|
475
|
+
symbols: ['executeBuiltinTool', 'validateBuiltinArgs'],
|
|
476
|
+
limit: 2,
|
|
477
|
+
}, root);
|
|
478
|
+
if (!/# symbol_search executeBuiltinTool\b/.test(String(graphSymbolBatchOut)) || !/# symbol_search validateBuiltinArgs\b/.test(String(graphSymbolBatchOut))) {
|
|
479
|
+
throw new Error(`code_graph symbol_search symbols[] batch execution failed:\n${graphSymbolBatchOut}`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const graphMissingFileOut = await executeCodeGraphTool('code_graph', {
|
|
483
|
+
mode: 'symbols',
|
|
484
|
+
file: 'src/runtime/loop.mjs',
|
|
485
|
+
}, root);
|
|
486
|
+
if (!/^Error: code_graph: file not found: src\/runtime\/loop\.mjs/.test(String(graphMissingFileOut))) {
|
|
487
|
+
throw new Error(`code_graph missing-file fast path failed:\n${graphMissingFileOut}`);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const graphDotDirOut = await executeCodeGraphTool('code_graph', {
|
|
491
|
+
mode: 'overview',
|
|
492
|
+
file: '.',
|
|
493
|
+
}, root);
|
|
494
|
+
assertOk('code_graph dot directory anchor', graphDotDirOut, /files\s+\d+|edges\s+\d+/i);
|
|
495
|
+
|
|
411
496
|
const patchOut = await executePatchTool('apply_patch', {
|
|
412
497
|
base_path: root,
|
|
413
498
|
dry_run: true,
|
|
@@ -498,6 +583,12 @@ if (literalBackslashPipeArray) {
|
|
|
498
583
|
throw new Error(`grep array literal \\| should be allowed: ${literalBackslashPipeArray}`);
|
|
499
584
|
}
|
|
500
585
|
|
|
586
|
+
const grepContextPolicyArgs = { pattern: 'smoke', path: root, context: GREP_CONTEXT_MAX + 999 };
|
|
587
|
+
applyGrepContextLeadPolicy(grepContextPolicyArgs);
|
|
588
|
+
if (grepContextPolicyArgs['-C'] !== GREP_CONTEXT_MAX || Object.prototype.hasOwnProperty.call(grepContextPolicyArgs, 'context')) {
|
|
589
|
+
throw new Error(`grep context policy must canonicalize and clamp explicit context: ${JSON.stringify(grepContextPolicyArgs)}`);
|
|
590
|
+
}
|
|
591
|
+
|
|
501
592
|
const invalidGrepPath = validateBuiltinArgs('grep', {
|
|
502
593
|
pattern: 'providerStatus',
|
|
503
594
|
path: 'C:\\Project\\mixdog\\src\\tui C:\\Project\\mixdog\\src\\mixdog-session-runtime.mjs',
|
|
@@ -514,11 +605,20 @@ if (!/lookaround\/backrefs/i.test(invalidGrepLookaround || '')) {
|
|
|
514
605
|
throw new Error(`grep unsupported-regex guard failed: ${invalidGrepLookaround}`);
|
|
515
606
|
}
|
|
516
607
|
|
|
517
|
-
|
|
608
|
+
// Windows drive path + no explicit shell used to be rejected with a retry hint;
|
|
609
|
+
// the guard now auto-coerces to shell:'powershell' (drive paths are a definitive
|
|
610
|
+
// powershell signal — they can never work under Git Bash unconverted).
|
|
611
|
+
const shellDrivePathArgs = {
|
|
518
612
|
command: 'cd C:\\Project\\mixdog && node scripts/build-tui.mjs',
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
613
|
+
};
|
|
614
|
+
const shellDrivePathErr = validateBuiltinArgs('shell', shellDrivePathArgs);
|
|
615
|
+
if (process.platform === 'win32') {
|
|
616
|
+
if (shellDrivePathErr !== null) {
|
|
617
|
+
throw new Error(`shell Windows-path auto-coercion failed: ${shellDrivePathErr}`);
|
|
618
|
+
}
|
|
619
|
+
if (shellDrivePathArgs.shell !== 'powershell') {
|
|
620
|
+
throw new Error(`shell Windows-path auto-coercion did not set shell:'powershell' (got ${JSON.stringify(shellDrivePathArgs.shell)})`);
|
|
621
|
+
}
|
|
522
622
|
}
|
|
523
623
|
|
|
524
624
|
const invalidShellCwdAliasConflict = validateBuiltinArgs('shell', {
|
|
@@ -534,16 +634,28 @@ if (!/cwd.*workdir.*conflict/i.test(invalidShellCwdAliasConflict || '')) {
|
|
|
534
634
|
const shellWorkdirOut = await shellWorkdirOutPromise;
|
|
535
635
|
assertOk('shell workdir alias', shellWorkdirOut, /scripts\s*$/i);
|
|
536
636
|
|
|
537
|
-
const
|
|
637
|
+
const offsetReadWindow = {
|
|
538
638
|
path: 'scripts/smoke.mjs',
|
|
539
|
-
|
|
540
|
-
context: 3,
|
|
541
|
-
offset: 1,
|
|
639
|
+
offset: 0,
|
|
542
640
|
limit: 20,
|
|
543
641
|
};
|
|
544
|
-
const readWindowErr = validateBuiltinArgs('read',
|
|
545
|
-
if (
|
|
546
|
-
throw new Error(`read
|
|
642
|
+
const readWindowErr = validateBuiltinArgs('read', offsetReadWindow);
|
|
643
|
+
if (readWindowErr) {
|
|
644
|
+
throw new Error(`read offset/limit window guard failed: err=${readWindowErr} args=${JSON.stringify(offsetReadWindow)}`);
|
|
645
|
+
}
|
|
646
|
+
const readLineArgs = { path: 'scripts/smoke.mjs', line: 10, context: 2 };
|
|
647
|
+
const readLineErr = validateBuiltinArgs('read', readLineArgs);
|
|
648
|
+
if (readLineErr || readLineArgs.offset !== 7 || readLineArgs.limit !== 5 || 'line' in readLineArgs || 'context' in readLineArgs) {
|
|
649
|
+
throw new Error(`read guard must losslessly convert top-level legacy line/context args to offset/limit: err=${readLineErr} args=${JSON.stringify(readLineArgs)}`);
|
|
650
|
+
}
|
|
651
|
+
const batchedReadLineArgs = { path: [{ path: 'scripts/smoke.mjs', line: 10, context: 2 }] };
|
|
652
|
+
const batchedReadLineErr = validateBuiltinArgs('read', batchedReadLineArgs);
|
|
653
|
+
if (batchedReadLineErr || batchedReadLineArgs.path[0].offset !== 7 || batchedReadLineArgs.path[0].limit !== 5) {
|
|
654
|
+
throw new Error(`read guard must losslessly convert batched legacy line/context args to offset/limit: err=${batchedReadLineErr} args=${JSON.stringify(batchedReadLineArgs)}`);
|
|
655
|
+
}
|
|
656
|
+
const pathLineWithLimit = normaliseReadLineWindowArgs({ path: 'scripts/smoke.mjs#L10', limit: 5 }, root);
|
|
657
|
+
if (pathLineWithLimit.offset !== 9 || pathLineWithLimit.limit !== 5) {
|
|
658
|
+
throw new Error(`read path#line compatibility must anchor offset when limit is explicit: ${JSON.stringify(pathLineWithLimit)}`);
|
|
547
659
|
}
|
|
548
660
|
|
|
549
661
|
function assertHas(set, name) {
|
|
@@ -630,27 +742,27 @@ const agentProps = AGENT_TOOL.inputSchema?.properties || {};
|
|
|
630
742
|
if (agentProps.mode || agentProps.wait) throw new Error('agent schema should not expose execution mode controls');
|
|
631
743
|
{
|
|
632
744
|
const heavyPrompt = composeSystemPrompt({
|
|
633
|
-
|
|
745
|
+
agent: 'heavy-worker',
|
|
634
746
|
provider: 'anthropic-oauth',
|
|
635
747
|
agentRules: '# Tool Use',
|
|
636
748
|
skillManifest: '',
|
|
637
749
|
});
|
|
638
|
-
if (!heavyPrompt.stableSystemContext.includes('## heavy-worker')
|
|
750
|
+
if (!heavyPrompt.stableSystemContext.includes('## heavy-worker')) {
|
|
639
751
|
throw new Error(`heavy-worker AGENT.md must be included in scoped role instructions: ${heavyPrompt.stableSystemContext}`);
|
|
640
752
|
}
|
|
641
753
|
const workerPrompt = composeSystemPrompt({
|
|
642
|
-
|
|
754
|
+
agent: 'worker',
|
|
643
755
|
provider: 'anthropic-oauth',
|
|
644
756
|
agentRules: '# Tool Use',
|
|
645
757
|
skillManifest: '',
|
|
646
758
|
});
|
|
647
|
-
if (!workerPrompt.stableSystemContext.includes('## worker')
|
|
759
|
+
if (!workerPrompt.stableSystemContext.includes('## worker')) {
|
|
648
760
|
throw new Error(`worker AGENT.md must be included in scoped role instructions: ${workerPrompt.stableSystemContext}`);
|
|
649
761
|
}
|
|
650
762
|
}
|
|
651
763
|
{
|
|
652
764
|
const shorthand = parseHeadlessRoleCommand(['reviewer', 'check', 'this']);
|
|
653
|
-
if (shorthand?.
|
|
765
|
+
if (shorthand?.agent !== 'reviewer' || shorthand?.message !== 'check this') {
|
|
654
766
|
throw new Error(`headless shorthand command parse failed: ${JSON.stringify(shorthand)}`);
|
|
655
767
|
}
|
|
656
768
|
const explicit = parseHeadlessRoleCommand(['role', 'debug', 'trace', 'failure']);
|
|
@@ -662,7 +774,7 @@ if (agentProps.mode || agentProps.wait) throw new Error('agent schema should not
|
|
|
662
774
|
throw new Error(`empty argv must keep TUI default: ${JSON.stringify(tuiDefault)}`);
|
|
663
775
|
}
|
|
664
776
|
const modelOnlySpawn = buildHeadlessSpawnArgs({
|
|
665
|
-
|
|
777
|
+
agent: 'reviewer',
|
|
666
778
|
tag: 'headless-smoke',
|
|
667
779
|
cwd: root,
|
|
668
780
|
message: 'check this',
|
|
@@ -672,7 +784,7 @@ if (agentProps.mode || agentProps.wait) throw new Error('agent schema should not
|
|
|
672
784
|
throw new Error(`headless model-only route must preserve --model without forcing provider: ${JSON.stringify(modelOnlySpawn)}`);
|
|
673
785
|
}
|
|
674
786
|
}
|
|
675
|
-
if (!/always start background tasks/i.test(AGENT_TOOL.description || '') || !/distinct tags/i.test(AGENT_TOOL.description || '') || !/completion notification/i.test(AGENT_TOOL.description || '') || !/do not (?:call|poll) status\/read/i.test(AGENT_TOOL.description || '')) {
|
|
787
|
+
if (!/always start background tasks/i.test(AGENT_TOOL.description || '') || !/distinct tags/i.test(AGENT_TOOL.description || '') || !/same scope/i.test(AGENT_TOOL.description || '') || !/send/i.test(AGENT_TOOL.description || '') || !/completion notification/i.test(AGENT_TOOL.description || '') || !/do not (?:call|poll) status\/read/i.test(AGENT_TOOL.description || '')) {
|
|
676
788
|
throw new Error('agent description must preserve async tagged delegation contract');
|
|
677
789
|
}
|
|
678
790
|
const agentSmoke = createStandaloneAgent({
|
|
@@ -846,6 +958,15 @@ if (EXPLORE_TOOL.annotations?.readOnlyHint !== true || EXPLORE_TOOL.annotations?
|
|
|
846
958
|
if (EXPLORE_TOOL.annotations?.agentHidden === true) {
|
|
847
959
|
throw new Error('explore must stay visible to agent sessions');
|
|
848
960
|
}
|
|
961
|
+
{
|
|
962
|
+
const runtimeSearchTool = __applyStandaloneToolDefaultsForTest(SEARCH_TOOL_DEFS.find((tool) => tool?.name === 'search'));
|
|
963
|
+
if (runtimeSearchTool?.annotations?.agentHidden === true) {
|
|
964
|
+
throw new Error('production search tool must stay visible to agent sessions');
|
|
965
|
+
}
|
|
966
|
+
if (TOOL_SEARCH_TOOL.annotations?.agentHidden !== true) {
|
|
967
|
+
throw new Error('deferred tool_search wrapper must stay hidden from agent sessions');
|
|
968
|
+
}
|
|
969
|
+
}
|
|
849
970
|
const exploreProps = EXPLORE_TOOL.inputSchema?.properties || {};
|
|
850
971
|
if (!/Repo anchor locator/i.test(EXPLORE_TOOL.description || '') || !/broad\/uncertain/i.test(EXPLORE_TOOL.description || '') || !/independent targets/i.test(EXPLORE_TOOL.description || '') || (EXPLORE_TOOL.description || '').length > 90) {
|
|
851
972
|
throw new Error('explore description must stay compact and anchor-oriented');
|
|
@@ -897,7 +1018,7 @@ setInternalToolsProvider({
|
|
|
897
1018
|
provider: 'openai-oauth',
|
|
898
1019
|
model: 'tool-smoke-model',
|
|
899
1020
|
owner: 'cli',
|
|
900
|
-
|
|
1021
|
+
agent: 'lead',
|
|
901
1022
|
cwd: skillManifestTmp,
|
|
902
1023
|
permission: 'read-write',
|
|
903
1024
|
});
|
|
@@ -917,7 +1038,7 @@ setInternalToolsProvider({
|
|
|
917
1038
|
provider: 'openai-oauth',
|
|
918
1039
|
model: 'tool-smoke-model',
|
|
919
1040
|
owner: AGENT_OWNER,
|
|
920
|
-
|
|
1041
|
+
agent: 'worker',
|
|
921
1042
|
cwd: skillManifestTmp,
|
|
922
1043
|
permission: 'read-write',
|
|
923
1044
|
});
|
|
@@ -938,8 +1059,8 @@ setInternalToolsProvider({
|
|
|
938
1059
|
throw new Error(`agent system layers must carry BP1 tool policy and BP2 role rules: ${systemVisible.slice(0, 1200)}`);
|
|
939
1060
|
}
|
|
940
1061
|
const agentSkillToolNames = (agentSkillSession.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
941
|
-
if (agentSkillToolNames.includes('Skill')) {
|
|
942
|
-
throw new Error(`read-write agent schema must
|
|
1062
|
+
if (!agentSkillToolNames.includes('Skill')) {
|
|
1063
|
+
throw new Error(`read-write agent schema must expose Skill loader with the manifest: ${agentSkillToolNames.join(', ')}`);
|
|
943
1064
|
}
|
|
944
1065
|
} finally {
|
|
945
1066
|
closeSession(agentSkillSession.id, 'tool-smoke');
|
|
@@ -951,7 +1072,7 @@ setInternalToolsProvider({
|
|
|
951
1072
|
provider: 'openai-oauth',
|
|
952
1073
|
model: 'tool-smoke-model',
|
|
953
1074
|
owner: AGENT_OWNER,
|
|
954
|
-
|
|
1075
|
+
agent: 'explorer',
|
|
955
1076
|
cwd: root,
|
|
956
1077
|
permission: 'read',
|
|
957
1078
|
skipSkills: true,
|
|
@@ -970,7 +1091,7 @@ setInternalToolsProvider({
|
|
|
970
1091
|
if (!/Read-only retrieval role/i.test(visible) || /# environment/i.test(visible) || /git operations deferred to Lead/i.test(visible)) {
|
|
971
1092
|
throw new Error(`explorer hidden retrieval context should stay slim: ${visible.slice(0, 1200)}`);
|
|
972
1093
|
}
|
|
973
|
-
if (!/# Role: explorer/i.test(systemVisible) || /# Role: explorer/i.test(userReminderVisible) || !/
|
|
1094
|
+
if (!/# Role: explorer/i.test(systemVisible) || /# Role: explorer/i.test(userReminderVisible) || !/one-shot locator/i.test(systemVisible)) {
|
|
974
1095
|
throw new Error(`explorer role md must ride BP2 system, not BP3 user reminder: system=${systemVisible.slice(0, 600)} user=${userReminderVisible.slice(0, 600)}`);
|
|
975
1096
|
}
|
|
976
1097
|
const visibleBytes = Buffer.byteLength(visible, 'utf8');
|
|
@@ -984,7 +1105,7 @@ setInternalToolsProvider({
|
|
|
984
1105
|
provider: 'openai-oauth',
|
|
985
1106
|
model: 'tool-smoke-model',
|
|
986
1107
|
owner: AGENT_OWNER,
|
|
987
|
-
|
|
1108
|
+
agent: 'worker',
|
|
988
1109
|
cwd: root,
|
|
989
1110
|
permission: 'read-write',
|
|
990
1111
|
taskBrief: 'Implement a scoped smoke check.',
|
|
@@ -1029,7 +1150,7 @@ setInternalToolsProvider({
|
|
|
1029
1150
|
provider: 'openai-oauth',
|
|
1030
1151
|
model: 'tool-smoke-model',
|
|
1031
1152
|
owner: AGENT_OWNER,
|
|
1032
|
-
|
|
1153
|
+
agent: 'worker',
|
|
1033
1154
|
cwd: root,
|
|
1034
1155
|
permission: 'read',
|
|
1035
1156
|
});
|
|
@@ -1037,7 +1158,7 @@ setInternalToolsProvider({
|
|
|
1037
1158
|
provider: 'openai-oauth',
|
|
1038
1159
|
model: 'tool-smoke-model',
|
|
1039
1160
|
owner: AGENT_OWNER,
|
|
1040
|
-
|
|
1161
|
+
agent: 'worker',
|
|
1041
1162
|
cwd: root,
|
|
1042
1163
|
permission: 'read-write',
|
|
1043
1164
|
});
|
|
@@ -1045,7 +1166,7 @@ setInternalToolsProvider({
|
|
|
1045
1166
|
provider: 'openai-oauth',
|
|
1046
1167
|
model: 'tool-smoke-model',
|
|
1047
1168
|
owner: AGENT_OWNER,
|
|
1048
|
-
|
|
1169
|
+
agent: 'worker',
|
|
1049
1170
|
cwd: root,
|
|
1050
1171
|
permission: 'full',
|
|
1051
1172
|
});
|
|
@@ -1062,8 +1183,8 @@ setInternalToolsProvider({
|
|
|
1062
1183
|
const writeTools = (writeAgentSession.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
1063
1184
|
const fullTools = (fullAgentSession.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
1064
1185
|
const publicExploreTools = (publicExploreSession.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
1065
|
-
const expectedReadTools = ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'explore', 'search', 'web_fetch'];
|
|
1066
|
-
const expectedWriteTools = ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'apply_patch', 'explore', 'search', 'web_fetch'];
|
|
1186
|
+
const expectedReadTools = ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'explore', 'search', 'web_fetch', 'Skill'];
|
|
1187
|
+
const expectedWriteTools = ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'apply_patch', 'explore', 'search', 'web_fetch', 'Skill'];
|
|
1067
1188
|
if (JSON.stringify(readTools) !== JSON.stringify(expectedReadTools)) {
|
|
1068
1189
|
throw new Error(`read agent schema must be fixed allow-list: expected=${expectedReadTools.join(', ')} actual=${readTools.join(', ')}`);
|
|
1069
1190
|
}
|
|
@@ -1076,7 +1197,7 @@ setInternalToolsProvider({
|
|
|
1076
1197
|
if (readTools.includes('shell') || writeTools.includes('shell')) {
|
|
1077
1198
|
throw new Error(`read/read-write agent schemas must omit shell: read=${readTools.join(', ')} write=${writeTools.join(', ')}`);
|
|
1078
1199
|
}
|
|
1079
|
-
for (const name of ['shell', 'apply_patch', 'task', 'diagnostics', 'open_config'
|
|
1200
|
+
for (const name of ['shell', 'apply_patch', 'task', 'diagnostics', 'open_config']) {
|
|
1080
1201
|
if (readTools.includes(name)) {
|
|
1081
1202
|
throw new Error(`read agent schema must omit non-read tool ${name}: read=${readTools.join(', ')}`);
|
|
1082
1203
|
}
|
|
@@ -1089,7 +1210,7 @@ setInternalToolsProvider({
|
|
|
1089
1210
|
throw new Error(`read-write agent schema must omit non-edit tool ${name}: write=${writeTools.join(', ')}`);
|
|
1090
1211
|
}
|
|
1091
1212
|
}
|
|
1092
|
-
for (const name of ['open_config'
|
|
1213
|
+
for (const name of ['open_config']) {
|
|
1093
1214
|
if (writeTools.includes(name)) {
|
|
1094
1215
|
throw new Error(`read-write agent schema must omit config/skill tool ${name}: write=${writeTools.join(', ')}`);
|
|
1095
1216
|
}
|
|
@@ -1121,14 +1242,14 @@ setInternalToolsProvider({
|
|
|
1121
1242
|
provider: 'openai-oauth',
|
|
1122
1243
|
model: 'tool-smoke-model',
|
|
1123
1244
|
owner: AGENT_OWNER,
|
|
1124
|
-
|
|
1245
|
+
agent: 'worker',
|
|
1125
1246
|
cwd: root,
|
|
1126
1247
|
permission: 'read-write',
|
|
1127
1248
|
});
|
|
1128
1249
|
try {
|
|
1129
1250
|
const resumed = await resumeSession(resumeAgentSession.id, 'full');
|
|
1130
1251
|
const resumedTools = (resumed?.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
1131
|
-
const expectedWriteTools = ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'apply_patch', 'explore', 'search', 'web_fetch'];
|
|
1252
|
+
const expectedWriteTools = ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'apply_patch', 'explore', 'search', 'web_fetch', 'Skill'];
|
|
1132
1253
|
if (JSON.stringify(resumedTools) !== JSON.stringify(expectedWriteTools)) {
|
|
1133
1254
|
throw new Error(`resumed read-write agent schema must keep fixed allow-list: expected=${expectedWriteTools.join(', ')} actual=${resumedTools.join(', ')}`);
|
|
1134
1255
|
}
|
|
@@ -1139,7 +1260,7 @@ setInternalToolsProvider({
|
|
|
1139
1260
|
provider: 'openai-oauth',
|
|
1140
1261
|
model: 'tool-smoke-model',
|
|
1141
1262
|
owner: AGENT_OWNER,
|
|
1142
|
-
|
|
1263
|
+
agent: 'worker',
|
|
1143
1264
|
cwd: root,
|
|
1144
1265
|
permission: 'none',
|
|
1145
1266
|
});
|
|
@@ -1156,7 +1277,7 @@ setInternalToolsProvider({
|
|
|
1156
1277
|
provider: 'openai-oauth',
|
|
1157
1278
|
model: 'tool-smoke-model',
|
|
1158
1279
|
owner: AGENT_OWNER,
|
|
1159
|
-
|
|
1280
|
+
agent: 'worker',
|
|
1160
1281
|
cwd: root,
|
|
1161
1282
|
permission: { allow: ['read', 'grep'], deny: ['grep'] },
|
|
1162
1283
|
});
|
|
@@ -1169,55 +1290,55 @@ setInternalToolsProvider({
|
|
|
1169
1290
|
} finally {
|
|
1170
1291
|
closeSession(objectPermissionSession.id, 'tool-smoke');
|
|
1171
1292
|
}
|
|
1172
|
-
const
|
|
1293
|
+
const hiddenAgents = JSON.parse(readFileSync(join(root, 'src', 'defaults', 'agents.json'), 'utf8')).agents || [];
|
|
1173
1294
|
const hiddenPreset = { id: 'hidden-smoke', name: 'hidden-smoke', type: 'agent', provider: 'openai-oauth', model: 'tool-smoke-model', tools: 'full' };
|
|
1174
1295
|
const hiddenRuntimeSpec = { scopeKey: 'hidden-role-smoke', lane: 'agent' };
|
|
1175
1296
|
const hiddenBadTools = new Set(['shell', 'task', 'diagnostics', 'open_config', 'Skill', 'memory', 'reply', 'edit_message', 'recall', 'reload_config', 'inject_command']);
|
|
1176
|
-
const
|
|
1297
|
+
const expectedForHiddenAgent = (permission, schemaAllowedTools) => {
|
|
1177
1298
|
if (Array.isArray(schemaAllowedTools)) return schemaAllowedTools.slice();
|
|
1178
1299
|
if (permission === 'none') return [];
|
|
1179
1300
|
if (permission === 'read') return ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'explore', 'search', 'web_fetch'];
|
|
1180
1301
|
if (permission === 'read-write') return ['code_graph', 'find', 'glob', 'list', 'grep', 'read', 'apply_patch', 'explore', 'search', 'web_fetch'];
|
|
1181
1302
|
return null;
|
|
1182
1303
|
};
|
|
1183
|
-
for (const entry of
|
|
1184
|
-
const
|
|
1185
|
-
if (!
|
|
1186
|
-
const hidden =
|
|
1187
|
-
const permission = resolveAgentSessionPermission(
|
|
1304
|
+
for (const entry of hiddenAgents) {
|
|
1305
|
+
const agent = String(entry?.agent || '').trim();
|
|
1306
|
+
if (!agent) continue;
|
|
1307
|
+
const hidden = getHiddenAgent(agent);
|
|
1308
|
+
const permission = resolveAgentSessionPermission(agent, hidden?.permission || null);
|
|
1188
1309
|
const schemaAllowedTools = resolveHiddenRoleSchemaAllowedTools(hidden);
|
|
1189
1310
|
const { session } = prepareAgentSession({
|
|
1190
|
-
|
|
1311
|
+
agent,
|
|
1191
1312
|
presetName: 'hidden-smoke',
|
|
1192
1313
|
preset: hiddenPreset,
|
|
1193
1314
|
runtimeSpec: hiddenRuntimeSpec,
|
|
1194
1315
|
permission,
|
|
1195
1316
|
cwd: root,
|
|
1196
1317
|
sourceType: 'hidden-role-smoke',
|
|
1197
|
-
sourceName:
|
|
1318
|
+
sourceName: agent,
|
|
1198
1319
|
schemaAllowedTools,
|
|
1199
1320
|
});
|
|
1200
1321
|
try {
|
|
1201
1322
|
const tools = (session.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
1202
1323
|
const resumed = await resumeSession(session.id, 'full');
|
|
1203
1324
|
const resumedTools = (resumed?.tools || []).map((tool) => tool?.name).filter(Boolean);
|
|
1204
|
-
const expected =
|
|
1325
|
+
const expected = expectedForHiddenAgent(permission, schemaAllowedTools);
|
|
1205
1326
|
if (expected && (JSON.stringify(tools) !== JSON.stringify(expected) || JSON.stringify(resumedTools) !== JSON.stringify(expected))) {
|
|
1206
|
-
throw new Error(`hidden
|
|
1327
|
+
throw new Error(`hidden agent ${agent} schema mismatch: expected=${expected.join(', ')} tools=${tools.join(', ')} resumed=${resumedTools.join(', ')}`);
|
|
1207
1328
|
}
|
|
1208
1329
|
const leaked = tools.filter((name) => hiddenBadTools.has(name) && !(expected || []).includes(name));
|
|
1209
1330
|
if (leaked.length) {
|
|
1210
|
-
throw new Error(`hidden
|
|
1331
|
+
throw new Error(`hidden agent ${agent} leaked forbidden full-runtime tools: ${leaked.join(', ')} from ${tools.join(', ')}`);
|
|
1211
1332
|
}
|
|
1212
1333
|
const systemVisible = (session.messages || [])
|
|
1213
1334
|
.filter((m) => m?.role === 'system')
|
|
1214
1335
|
.map((m) => String(m.content || ''))
|
|
1215
1336
|
.join('\n');
|
|
1216
1337
|
if (/available-skills|Skill\(/i.test(systemVisible)) {
|
|
1217
|
-
throw new Error(`hidden
|
|
1338
|
+
throw new Error(`hidden agent ${agent} must not carry Skill manifest without Skill tool`);
|
|
1218
1339
|
}
|
|
1219
1340
|
if (/effective-cwd|Override cwd|# environment|# task-brief/i.test(systemVisible)) {
|
|
1220
|
-
throw new Error(`hidden
|
|
1341
|
+
throw new Error(`hidden agent ${agent} must not carry cwd/environment/task-brief injection`);
|
|
1221
1342
|
}
|
|
1222
1343
|
} finally {
|
|
1223
1344
|
closeSession(session.id, 'tool-smoke');
|
|
@@ -1311,21 +1432,93 @@ for (const requiredGrammarLine of [
|
|
|
1311
1432
|
throw new Error(`custom apply_patch SSE parser must eager-emit patch args: ${JSON.stringify(emitted)}`);
|
|
1312
1433
|
}
|
|
1313
1434
|
}
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1435
|
+
const readPathSchema = BUILTIN_TOOLS.find((tool) => tool.name === 'read')?.inputSchema?.properties?.path || {};
|
|
1436
|
+
const readPathDescription = readPathSchema.description || '';
|
|
1437
|
+
if (!/File path/i.test(readPathDescription) || !/\{path,offset,limit\}\[\]/i.test(readPathDescription) || !/Pass arrays directly/i.test(readPathDescription) || !/legacy recovery only/i.test(readPathDescription)) {
|
|
1316
1438
|
throw new Error('read schema must keep directory-vs-file guidance');
|
|
1317
1439
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1440
|
+
if (!/Dirs use list/i.test((BUILTIN_TOOLS.find((tool) => tool.name === 'read')?.description) || '')) {
|
|
1441
|
+
throw new Error('read description must keep directory-vs-file guidance');
|
|
1442
|
+
}
|
|
1443
|
+
const readTool = BUILTIN_TOOLS.find((tool) => tool.name === 'read');
|
|
1444
|
+
const readDescription = readTool?.description || '';
|
|
1445
|
+
const readProps = readTool?.inputSchema?.properties || {};
|
|
1446
|
+
const readArraySchema = readPathSchema.anyOf?.find((entry) => entry?.type === 'array');
|
|
1447
|
+
const readArrayItemAnyOf = readArraySchema?.items?.anyOf || [];
|
|
1448
|
+
if (!readArrayItemAnyOf.some((entry) => entry?.type === 'object' && entry?.properties?.offset && entry?.properties?.limit)) {
|
|
1449
|
+
throw new Error('read schema must expose array-of-region objects for batched spans');
|
|
1450
|
+
}
|
|
1451
|
+
if (/line\+context/i.test(readDescription) || !/numeric offset\+limit/i.test(readDescription) || !/Batch paths\/regions as real arrays/i.test(readDescription) || !/grep content_with_context or code_graph anchors/i.test(readDescription)) {
|
|
1452
|
+
throw new Error('read description must expose offset/limit as the single window form');
|
|
1453
|
+
}
|
|
1454
|
+
if (readProps.line || readProps.context) {
|
|
1455
|
+
throw new Error('read schema must not expose legacy line/context window fields');
|
|
1456
|
+
}
|
|
1457
|
+
if (readProps.offset?.minimum !== 0 || !/Numeric lines to skip/i.test(readProps.offset?.description || '') || !/offset:N/i.test(readProps.offset?.description || '') || !/Numeric max lines/i.test(readProps.limit?.description || '')) {
|
|
1458
|
+
throw new Error('read offset schema must describe Mixdog paging cursor semantics');
|
|
1459
|
+
}
|
|
1460
|
+
if (/line\/context/i.test(JSON.stringify(readTool?.inputSchema || {}))) {
|
|
1461
|
+
throw new Error('read schema surface must not mention legacy line/context');
|
|
1462
|
+
}
|
|
1463
|
+
{
|
|
1464
|
+
const benchRunSrc = readFileSync(resolve(root, 'scripts/bench-run.mjs'), 'utf8');
|
|
1465
|
+
if (!/task_complete:\s*results\.length > 0 && completed === results\.length/.test(benchRunSrc)) {
|
|
1466
|
+
throw new Error('bench-run must require every task to complete before saving a round');
|
|
1467
|
+
}
|
|
1468
|
+
if (!/score_complete:\s*results\.length > 0 && taskErrors\.length === 0 && scoreErrors\.length === 0 && \(score\?\.cards\?\.length \|\| 0\) === results\.length/.test(benchRunSrc)) {
|
|
1469
|
+
throw new Error('bench-run must require a scorecard for every task before saving a round');
|
|
1470
|
+
}
|
|
1471
|
+
if (!/not saving incomplete round/.test(benchRunSrc) || !/process\.exit\(1\)/.test(benchRunSrc)) {
|
|
1472
|
+
throw new Error('bench-run must not save incomplete rounds and must exit non-zero');
|
|
1473
|
+
}
|
|
1474
|
+
const taskBenchSrc = readFileSync(resolve(root, 'scripts/task-bench.mjs'), 'utf8');
|
|
1475
|
+
if (!/const allowPartial = hasFlag\('--allow-partial'\)/.test(taskBenchSrc) || !/skipped\.length && !allowPartial/.test(taskBenchSrc) || !/process\.exit\(1\)/.test(taskBenchSrc)) {
|
|
1476
|
+
throw new Error('task-bench must fail partial scoring unless --allow-partial is explicit');
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
{
|
|
1480
|
+
// setRoute must default to "next session only": a bare
|
|
1481
|
+
// runtime.setRoute({model}) call (no options) must NOT rewrite a live
|
|
1482
|
+
// session's provider/model in place, or a mid-conversation model/provider
|
|
1483
|
+
// switch silently forces a full prompt-cache rewrite (seen as a
|
|
1484
|
+
// promptΔ spike + cache_ratio=0% turn in session-bench).
|
|
1485
|
+
const runtimeSrc = readFileSync(resolve(root, 'src/mixdog-session-runtime.mjs'), 'utf8');
|
|
1486
|
+
const setRouteBlock = runtimeSrc.match(/async setRoute\(next, options = \{\}\) \{[\s\S]*?\n \},\n/)?.[0] || '';
|
|
1487
|
+
if (!/applyToCurrentSession = options\?\.applyToCurrentSession === true/.test(setRouteBlock)) {
|
|
1488
|
+
throw new Error('setRoute must default applyToCurrentSession to false (model changes apply to the next session only)');
|
|
1489
|
+
}
|
|
1490
|
+
if (!/if \(!applyToCurrentSession\)/.test(setRouteBlock) || !/return route;/.test(setRouteBlock)) {
|
|
1491
|
+
throw new Error('setRoute must early-return before touching the live session when applyToCurrentSession is false');
|
|
1492
|
+
}
|
|
1493
|
+
const engineSrc = readFileSync(resolve(root, 'src/tui/engine.mjs'), 'utf8');
|
|
1494
|
+
if (/setRoute\(\{ model: m \}, \{ applyToCurrentSession: true \}\)/.test(engineSrc)) {
|
|
1495
|
+
throw new Error('TUI setModel must not force applyToCurrentSession:true (model changes must apply to the next session only)');
|
|
1496
|
+
}
|
|
1497
|
+
if (!/routeOpts\.applyToCurrentSession === true/.test(engineSrc)) {
|
|
1498
|
+
throw new Error('TUI setRoute wrapper must default applyToCurrentSession to false');
|
|
1499
|
+
}
|
|
1321
1500
|
}
|
|
1322
1501
|
const codeGraphDescription = CODE_GRAPH_TOOL_DEFS[0]?.description || '';
|
|
1323
1502
|
const codeGraphProps = CODE_GRAPH_TOOL_DEFS[0]?.inputSchema?.properties || {};
|
|
1324
|
-
|
|
1325
|
-
|
|
1503
|
+
const codeGraphSymbolSearchErr = validateBuiltinArgs('code_graph', { mode: 'symbol_search', symbols: ['hook', 'deny'], limit: 5 });
|
|
1504
|
+
if (codeGraphSymbolSearchErr) {
|
|
1505
|
+
throw new Error(`code_graph guard must accept symbol_search with symbols[] batching: ${codeGraphSymbolSearchErr}`);
|
|
1506
|
+
}
|
|
1507
|
+
// code_graph description stays structure-oriented and must actively route
|
|
1508
|
+
// symbol/definition/caller lookups AWAY from repeated grep (the grep_retry +
|
|
1509
|
+
// find_symbol_noscope anti-patterns). It is allowed to be verbose enough to
|
|
1510
|
+
// enumerate modes, but must not drift into web-search territory.
|
|
1511
|
+
if (!/code structure\/flow/i.test(codeGraphDescription) || !/symbols\/references\/calls\/deps/i.test(codeGraphDescription)) {
|
|
1512
|
+
throw new Error('code_graph description must stay structure-oriented and name its symbol modes');
|
|
1513
|
+
}
|
|
1514
|
+
if (!/before text grep/i.test(codeGraphDescription)) {
|
|
1515
|
+
throw new Error('code_graph description must steer symbol/caller lookups to structure lookup before grep');
|
|
1326
1516
|
}
|
|
1327
|
-
if (
|
|
1328
|
-
throw new Error('code_graph
|
|
1517
|
+
if (!/repo-local/i.test(codeGraphDescription) || !/NOT web search|not web/i.test(codeGraphDescription)) {
|
|
1518
|
+
throw new Error('code_graph description must mark itself repo-local (not web search)');
|
|
1519
|
+
}
|
|
1520
|
+
if (!/repo-local|not web/i.test(codeGraphProps.mode?.description || '') || !/source file/i.test(codeGraphProps.file?.description || '')) {
|
|
1521
|
+
throw new Error('code_graph schema must keep compact, repo-local field descriptions');
|
|
1329
1522
|
}
|
|
1330
1523
|
const recallTool = MEMORY_TOOL_DEFS.find((tool) => tool.name === 'recall');
|
|
1331
1524
|
const recallProps = recallTool?.inputSchema?.properties || {};
|
|
@@ -1572,13 +1765,63 @@ if (!/NOT for URLs/i.test(fetchTool?.description || '') || !/web_fetch/i.test(fe
|
|
|
1572
1765
|
const grepTool = BUILTIN_TOOLS.find((tool) => tool.name === 'grep');
|
|
1573
1766
|
const grepPatternDescription = grepTool?.inputSchema?.properties?.pattern?.description || '';
|
|
1574
1767
|
const grepPathDescription = grepTool?.inputSchema?.properties?.path?.description || '';
|
|
1575
|
-
|
|
1768
|
+
const grepGlobDescription = grepTool?.inputSchema?.properties?.glob?.description || '';
|
|
1769
|
+
const grepOutputModeDescription = grepTool?.inputSchema?.properties?.output_mode?.description || '';
|
|
1770
|
+
const grepHeadLimitDescription = grepTool?.inputSchema?.properties?.head_limit?.description || '';
|
|
1771
|
+
if (!/synonyms in pattern\[\]/i.test(grepPatternDescription) || !/OR in ONE grep/i.test(grepPatternDescription) || !/serial rewording/i.test(grepPatternDescription) || !/equivalent repeats/i.test(grepPatternDescription) || !/Narrowest file\/dir/i.test(grepPathDescription) || !/broad scopes return paths first/i.test(grepPathDescription) || !/refine from returned paths/i.test(grepPathDescription)) {
|
|
1576
1772
|
throw new Error('grep schema must keep compact pattern/path guidance');
|
|
1577
1773
|
}
|
|
1774
|
+
if (!/same grep/i.test(grepGlobDescription) || !/no follow-up grep/i.test(grepGlobDescription) || !/equivalent scope changes/i.test(grepGlobDescription)) {
|
|
1775
|
+
throw new Error('grep glob schema must steer narrowing into the same grep call');
|
|
1776
|
+
}
|
|
1777
|
+
if (!/Broad scope: files_with_matches\/count/i.test(grepOutputModeDescription) || !/Narrow scope: content_with_context/i.test(grepOutputModeDescription) || !/answer from/i.test(grepOutputModeDescription) || !/skip read/i.test(grepOutputModeDescription) || !/span is not shown/i.test(grepOutputModeDescription)) {
|
|
1778
|
+
throw new Error('grep output_mode schema must steer content_with_context away from follow-up reads');
|
|
1779
|
+
}
|
|
1780
|
+
if (grepTool?.inputSchema?.properties?.head_limit?.minimum !== 0 || !/keep small/i.test(grepHeadLimitDescription)) {
|
|
1781
|
+
throw new Error('grep head_limit schema must keep locator caps explicit');
|
|
1782
|
+
}
|
|
1783
|
+
if (grepTool?.inputSchema?.properties?.type) {
|
|
1784
|
+
throw new Error('grep type schema must stay hidden; prefer glob for extension narrowing');
|
|
1785
|
+
}
|
|
1786
|
+
if (!/code flow before text search/i.test(codeGraphProps.mode?.description || '') || !/one anchor is enough/i.test(codeGraphProps.symbol?.description || '') || !/one call/i.test(codeGraphProps.symbols?.description || '')) {
|
|
1787
|
+
throw new Error('code_graph schema fields must steer away from repeated lookup loops');
|
|
1788
|
+
}
|
|
1578
1789
|
|
|
1579
1790
|
const longToolSearchText = compactToolSearchDescription(`${patchDescription}\n${patchDescription}`);
|
|
1580
1791
|
if (longToolSearchText.length > 220 || /\n/.test(longToolSearchText)) {
|
|
1581
1792
|
throw new Error(`tool_search descriptions must be compact single-line snippets, got ${longToolSearchText.length} chars`);
|
|
1582
1793
|
}
|
|
1583
1794
|
|
|
1795
|
+
{
|
|
1796
|
+
// Regression guard for the sonnet-5 16384 cap bug (thinking exhausted the
|
|
1797
|
+
// whole output budget). Both the catalog path (outputTokens=128000 → capped
|
|
1798
|
+
// 65536) and the catalog-miss heuristic (sonnet 5+ → 65536) must yield
|
|
1799
|
+
// 65536, so assert the exact value with the env override cleared.
|
|
1800
|
+
const _prevMaxOut = process.env.MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS;
|
|
1801
|
+
delete process.env.MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS;
|
|
1802
|
+
try {
|
|
1803
|
+
const sonnet5MaxTokens = _anthropicOAuthTest.resolveMaxTokens('claude-sonnet-5');
|
|
1804
|
+
if (sonnet5MaxTokens !== 65536) {
|
|
1805
|
+
throw new Error(`resolveMaxTokens('claude-sonnet-5') must be 65536 (catalog-capped or sonnet-5+ fallback), got ${sonnet5MaxTokens}`);
|
|
1806
|
+
}
|
|
1807
|
+
const sonnet46MaxTokens = _anthropicOAuthTest.resolveMaxTokens('claude-sonnet-4-6');
|
|
1808
|
+
if (!(sonnet46MaxTokens >= 16384)) {
|
|
1809
|
+
throw new Error(`resolveMaxTokens('claude-sonnet-4-6') must be >= 16384, got ${sonnet46MaxTokens}`);
|
|
1810
|
+
}
|
|
1811
|
+
process.env.MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS = 'garbage';
|
|
1812
|
+
const garbageOverride = _anthropicOAuthTest.resolveMaxTokens('claude-sonnet-5');
|
|
1813
|
+
if (garbageOverride !== 65536) {
|
|
1814
|
+
throw new Error(`invalid MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS must be ignored (catalog/fallback path), got ${garbageOverride}`);
|
|
1815
|
+
}
|
|
1816
|
+
process.env.MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS = '32768';
|
|
1817
|
+
const validOverride = _anthropicOAuthTest.resolveMaxTokens('claude-sonnet-5');
|
|
1818
|
+
if (validOverride !== 32768) {
|
|
1819
|
+
throw new Error(`valid MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS=32768 must win, got ${validOverride}`);
|
|
1820
|
+
}
|
|
1821
|
+
} finally {
|
|
1822
|
+
if (_prevMaxOut === undefined) delete process.env.MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS;
|
|
1823
|
+
else process.env.MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS = _prevMaxOut;
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1584
1827
|
process.stdout.write(`tool smoke passed surface_chars=${surfaceSize}\n`);
|