mixdog 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -23
- package/package.json +33 -27
- package/scripts/_test-folder-dialog.mjs +30 -0
- package/scripts/agent-parallel-smoke.mjs +388 -0
- package/scripts/agent-tag-reuse-smoke.mjs +183 -0
- package/scripts/background-task-meta-smoke.mjs +38 -0
- package/scripts/boot-smoke.mjs +52 -9
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/compact-active-turn-test.mjs +68 -0
- package/scripts/compact-smoke.mjs +859 -129
- package/scripts/compact-trigger-migration-smoke.mjs +187 -0
- package/scripts/fix-brief-fn.mjs +35 -0
- package/scripts/fix-format-tool-surface.mjs +24 -0
- package/scripts/fix-tool-exec-visible.mjs +42 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/hook-bus-test.mjs +330 -0
- package/scripts/lead-workflow-smoke.mjs +33 -39
- package/scripts/live-worker-smoke.mjs +43 -37
- package/scripts/llm-trace-summary.mjs +315 -0
- package/scripts/memory-meta-concurrency-test.mjs +20 -0
- package/scripts/output-style-smoke.mjs +56 -15
- package/scripts/parent-abort-link-test.mjs +44 -0
- package/scripts/patch-agent-brief.mjs +48 -0
- package/scripts/patch-app.mjs +21 -0
- package/scripts/patch-app2.mjs +18 -0
- package/scripts/patch-dist-brief.mjs +96 -0
- package/scripts/patch-tool-exec.mjs +70 -0
- package/scripts/pretool-ask-runtime-test.mjs +54 -0
- package/scripts/provider-toolcall-test.mjs +376 -0
- package/scripts/reactive-compact-persist-smoke.mjs +124 -0
- package/scripts/sanitize-tool-pairs-test.mjs +260 -0
- package/scripts/session-context-bench.mjs +344 -0
- package/scripts/session-ingest-smoke.mjs +177 -0
- package/scripts/set-effort-config-test.mjs +41 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -0
- package/scripts/smoke-runtime-negative.sh +97 -0
- package/scripts/smoke.mjs +25 -0
- package/scripts/tool-result-hook-test.mjs +48 -0
- package/scripts/tool-smoke.mjs +1223 -95
- package/scripts/toolcall-args-test.mjs +150 -0
- package/scripts/tui-background-failure-smoke.mjs +73 -0
- package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
- package/src/agents/debugger/AGENT.md +8 -0
- package/src/agents/explore/AGENT.md +4 -0
- package/src/agents/heavy-worker/AGENT.md +9 -3
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +8 -0
- package/src/agents/scheduler-task/AGENT.md +12 -0
- package/src/agents/scheduler-task/agent.json +6 -0
- package/src/agents/webhook-handler/AGENT.md +12 -0
- package/src/agents/webhook-handler/agent.json +6 -0
- package/src/agents/worker/AGENT.md +9 -3
- package/src/app.mjs +77 -3
- package/src/defaults/hidden-roles.json +17 -12
- package/src/headless-role.mjs +117 -0
- package/src/help.mjs +30 -0
- package/src/hooks/lib/permission-evaluator.cjs +11 -475
- package/src/lib/keychain-cjs.cjs +9 -1
- package/src/lib/mixdog-debug.cjs +0 -7
- package/src/lib/rules-builder.cjs +240 -96
- package/src/lib/text-utils.cjs +1 -1
- package/src/mixdog-session-runtime.mjs +2325 -450
- package/src/output-styles/default.md +12 -28
- package/src/output-styles/extreme-simple.md +9 -6
- package/src/output-styles/simple.md +22 -9
- package/src/repl.mjs +118 -59
- package/src/rules/agent/00-common.md +15 -0
- package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
- package/src/rules/agent/30-explorer.md +22 -0
- package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
- package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
- package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
- package/src/rules/lead/01-general.md +9 -5
- package/src/rules/lead/04-workflow.md +51 -12
- package/src/rules/lead/lead-tool.md +6 -0
- package/src/rules/shared/01-tool.md +12 -1
- package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
- package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
- package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
- package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
- package/src/runtime/agent/orchestrator/config.mjs +174 -55
- package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
- package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
- package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +377 -243
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +146 -93
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +221 -70
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +477 -147
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -496
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +31 -11
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
- package/src/runtime/agent/orchestrator/session/loop.mjs +851 -674
- package/src/runtime/agent/orchestrator/session/manager.mjs +1593 -466
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +291 -46
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
- package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +34 -7
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +9 -9
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
- package/src/runtime/channels/index.mjs +152 -24
- package/src/runtime/channels/lib/scheduler.mjs +18 -14
- package/src/runtime/channels/lib/session-discovery.mjs +3 -2
- package/src/runtime/channels/lib/tool-format.mjs +0 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +3 -2
- package/src/runtime/channels/lib/webhook.mjs +1 -1
- package/src/runtime/channels/tool-defs.mjs +29 -29
- package/src/runtime/memory/index.mjs +635 -107
- package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
- package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
- package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
- package/src/runtime/memory/lib/memory-cycle1.mjs +38 -17
- package/src/runtime/memory/lib/memory-cycle2.mjs +6 -7
- package/src/runtime/memory/lib/memory-cycle3.mjs +4 -4
- package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
- package/src/runtime/memory/lib/memory.mjs +88 -9
- package/src/runtime/memory/lib/model-profile.mjs +1 -1
- package/src/runtime/memory/lib/pg/adapter.mjs +15 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +37 -3
- package/src/runtime/memory/lib/session-ingest.mjs +194 -0
- package/src/runtime/memory/lib/trace-store.mjs +96 -51
- package/src/runtime/memory/tool-defs.mjs +46 -37
- package/src/runtime/search/index.mjs +102 -466
- package/src/runtime/search/lib/web-tools.mjs +45 -25
- package/src/runtime/search/tool-defs.mjs +16 -23
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +4 -3
- package/src/runtime/shared/background-tasks.mjs +122 -11
- package/src/runtime/shared/child-spawn-gate.mjs +145 -0
- package/src/runtime/shared/config.mjs +7 -4
- package/src/runtime/shared/err-text.mjs +131 -4
- package/src/runtime/shared/llm/cost.mjs +2 -2
- package/src/runtime/shared/llm/http-agent.mjs +23 -7
- package/src/runtime/shared/llm/index.mjs +34 -11
- package/src/runtime/shared/llm/usage-log.mjs +4 -4
- package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
- package/src/runtime/shared/singleton-owner.mjs +104 -0
- package/src/runtime/shared/tool-execution-contract.mjs +199 -20
- package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
- package/src/runtime/shared/tool-surface.mjs +624 -98
- package/src/runtime/shared/user-data-guard.mjs +0 -2
- package/src/standalone/agent-task-status.mjs +203 -0
- package/src/standalone/agent-task-status.test.mjs +76 -0
- package/src/standalone/agent-tool.mjs +1913 -0
- package/src/standalone/channel-worker.mjs +370 -14
- package/src/standalone/explore-tool.mjs +165 -70
- package/src/standalone/folder-dialog.mjs +314 -0
- package/src/standalone/hook-bus.mjs +898 -22
- package/src/standalone/memory-runtime-proxy.mjs +320 -0
- package/src/standalone/projects.mjs +226 -0
- package/src/standalone/provider-admin.mjs +41 -24
- package/src/standalone/seeds.mjs +2 -69
- package/src/standalone/usage-dashboard.mjs +96 -8
- package/src/tui/App.jsx +4798 -2153
- package/src/tui/components/AnsiText.jsx +39 -28
- package/src/tui/components/ContextPanel.jsx +87 -29
- package/src/tui/components/Markdown.jsx +43 -77
- package/src/tui/components/MarkdownTable.jsx +9 -184
- package/src/tui/components/Message.jsx +28 -11
- package/src/tui/components/Picker.jsx +95 -56
- package/src/tui/components/PromptInput.jsx +367 -239
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +27 -21
- package/src/tui/components/Spinner.jsx +67 -38
- package/src/tui/components/StatusLine.jsx +606 -38
- package/src/tui/components/TextEntryPanel.jsx +128 -9
- package/src/tui/components/ToolExecution.jsx +617 -368
- package/src/tui/components/TurnDone.jsx +3 -3
- package/src/tui/components/UsagePanel.jsx +3 -5
- package/src/tui/components/tool-output-format.mjs +365 -0
- package/src/tui/components/tool-output-format.test.mjs +220 -0
- package/src/tui/dist/index.mjs +8915 -2418
- package/src/tui/engine-runtime-notification.test.mjs +115 -0
- package/src/tui/engine-tool-result-text.test.mjs +75 -0
- package/src/tui/engine.mjs +1455 -279
- package/src/tui/figures.mjs +21 -40
- package/src/tui/index.jsx +75 -31
- package/src/tui/input-editing.mjs +25 -0
- package/src/tui/markdown/format-token.mjs +511 -68
- package/src/tui/markdown/format-token.test.mjs +216 -0
- package/src/tui/markdown/render-ansi.mjs +94 -0
- package/src/tui/markdown/render-ansi.test.mjs +108 -0
- package/src/tui/markdown/stream-fence.mjs +34 -0
- package/src/tui/markdown/stream-fence.test.mjs +26 -0
- package/src/tui/markdown/table-layout.mjs +250 -0
- package/src/tui/paste-attachments.mjs +0 -7
- package/src/tui/spinner-verbs.mjs +1 -2
- package/src/tui/statusline-ansi-bridge.mjs +172 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
- package/src/tui/theme.mjs +746 -24
- package/src/tui/time-format.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +67 -0
- package/src/tui/transcript-tool-failures.test.mjs +111 -0
- package/src/ui/ansi.mjs +1 -2
- package/src/ui/markdown.mjs +85 -26
- package/src/ui/markdown.test.mjs +70 -0
- package/src/ui/model-display.mjs +121 -0
- package/src/ui/session-stats.mjs +44 -0
- package/src/ui/statusline-context-label.test.mjs +15 -0
- package/src/ui/statusline.mjs +386 -178
- package/src/ui/tool-card.mjs +3 -16
- package/src/vendor/statusline/bin/statusline-lib.mjs +8 -4
- package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
- package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
- package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +12 -5
- package/src/workflows/default/workflow.json +0 -1
- package/src/workflows/solo/WORKFLOW.md +15 -0
- package/src/workflows/solo/workflow.json +7 -0
- package/vendor/ink/build/output.js +6 -1
- package/src/agents/scheduler-task.md +0 -3
- package/src/agents/web-researcher/AGENT.md +0 -3
- package/src/agents/web-researcher/agent.json +0 -6
- package/src/agents/webhook-handler.md +0 -3
- package/src/rules/bridge/00-common.md +0 -5
- package/src/rules/bridge/30-explorer.md +0 -4
- package/src/rules/lead/00-tool-lead.md +0 -5
- package/src/rules/shared/00-language.md +0 -3
- package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
- package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
- package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
- package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
- package/src/standalone/bridge-tool.mjs +0 -1414
- package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
|
@@ -1,23 +1,50 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { loadConfig } from '../config.mjs';
|
|
3
3
|
import { sanitizeToolPairs, sanitizeAnthropicContentPairs } from '../session/context-utils.mjs';
|
|
4
|
-
import { classifyError, withRetry } from './retry-classifier.mjs';
|
|
5
|
-
import {
|
|
4
|
+
import { classifyError, midstreamBackoffFor, withRetry } from './retry-classifier.mjs';
|
|
5
|
+
import { traceAgentUsage } from '../agent-trace.mjs';
|
|
6
6
|
import {
|
|
7
7
|
PROVIDER_FIRST_BYTE_TIMEOUT_MS,
|
|
8
8
|
createTimeoutSignal,
|
|
9
9
|
createPassthroughSignal,
|
|
10
10
|
} from '../stall-policy.mjs';
|
|
11
11
|
import { createAbortController } from '../../../shared/abort-controller.mjs';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ANTHROPIC_MAX_MIDSTREAM_RETRIES,
|
|
14
|
+
parseSSEStream,
|
|
15
|
+
_classifyMidstreamError,
|
|
16
|
+
} from './anthropic-oauth.mjs';
|
|
13
17
|
import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
|
|
14
18
|
import { normalizeContentForAnthropic } from './media-normalization.mjs';
|
|
15
19
|
import { enrichModels } from './model-catalog.mjs';
|
|
16
20
|
import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
async function _midstreamSleepWithAbort(ms, signal) {
|
|
23
|
+
if (!ms) return;
|
|
24
|
+
if (!signal) {
|
|
25
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await new Promise((resolve, reject) => {
|
|
29
|
+
const t = setTimeout(() => {
|
|
30
|
+
try { signal.removeEventListener('abort', onAbort); } catch {}
|
|
31
|
+
resolve();
|
|
32
|
+
}, ms);
|
|
33
|
+
const onAbort = () => {
|
|
34
|
+
clearTimeout(t);
|
|
35
|
+
const reason = signal.reason;
|
|
36
|
+
reject(reason instanceof Error ? reason : new Error('Anthropic mid-stream retry backoff aborted'));
|
|
37
|
+
};
|
|
38
|
+
if (signal.aborted) { onAbort(); return; }
|
|
39
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 4-BP cache policy aligned with anthropic-oauth — system + tier3 +
|
|
44
|
+
// messages-tail. Tool schemas sit before system and are covered by the system
|
|
45
|
+
// breakpoint, so they do not spend a separate cache_control slot. 1h TTL
|
|
46
|
+
// requires the extended-cache-ttl beta header, which we set on the client via
|
|
47
|
+
// defaultHeaders below.
|
|
21
48
|
const CACHE_TTL_STABLE = { type: 'ephemeral', ttl: '1h' };
|
|
22
49
|
const CACHE_TTL_VOLATILE = { type: 'ephemeral' };
|
|
23
50
|
|
|
@@ -39,23 +66,9 @@ function appendCacheControl(content, ttl = CACHE_TTL_VOLATILE) {
|
|
|
39
66
|
return content;
|
|
40
67
|
}
|
|
41
68
|
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
// message) deliberately omits the sentinel so it stays on the message tail.
|
|
46
|
-
const BP3_SENTINEL = '<!-- bp3-sentinel -->';
|
|
47
|
-
|
|
48
|
-
function findTier3Index(chatMsgs) {
|
|
49
|
-
for (let i = 0; i < chatMsgs.length; i++) {
|
|
50
|
-
const m = chatMsgs[i];
|
|
51
|
-
if (m?.role === 'user' && typeof m.content === 'string'
|
|
52
|
-
&& m.content.startsWith('<system-reminder>')
|
|
53
|
-
&& m.content.includes(BP3_SENTINEL)) {
|
|
54
|
-
return i;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return -1;
|
|
58
|
-
}
|
|
69
|
+
// BP3 (tier3) rides its own `system` role block (the 3rd system block, tagged
|
|
70
|
+
// cacheTier:'tier3'). buildSystemBlocks applies the tier3 1h cache_control to
|
|
71
|
+
// that block; BP1/BP2 take the system TTL. Mirrors anthropic-oauth.mjs.
|
|
59
72
|
|
|
60
73
|
function resolveCacheTtls(opts) {
|
|
61
74
|
const strategy = opts?.cacheStrategy || {};
|
|
@@ -67,19 +80,40 @@ function resolveCacheTtls(opts) {
|
|
|
67
80
|
return fallback;
|
|
68
81
|
};
|
|
69
82
|
return {
|
|
70
|
-
tools: pick('tools',
|
|
83
|
+
tools: pick('tools', null),
|
|
71
84
|
system: pick('system', CACHE_TTL_STABLE),
|
|
72
85
|
tier3: pick('tier3', CACHE_TTL_STABLE),
|
|
73
86
|
messages: pick('messages', CACHE_TTL_STABLE),
|
|
74
87
|
};
|
|
75
88
|
}
|
|
76
89
|
|
|
90
|
+
function buildSystemBlocks(systemMsgs, systemTtl, tier3Ttl) {
|
|
91
|
+
// systemMsgs is an array of { content, cacheTier }. Each non-empty element
|
|
92
|
+
// becomes its own content block: cacheTier:'tier3' (BP3 sessionMarker) gets
|
|
93
|
+
// tier3Ttl, every other block (BP1/BP2) gets systemTtl. A null TTL leaves
|
|
94
|
+
// the corresponding block uncached.
|
|
95
|
+
const items = Array.isArray(systemMsgs)
|
|
96
|
+
? systemMsgs
|
|
97
|
+
.map(m => ({
|
|
98
|
+
text: typeof m?.content === 'string' ? m.content.trim() : '',
|
|
99
|
+
tier: m?.cacheTier === 'tier3' ? 'tier3' : 'system',
|
|
100
|
+
}))
|
|
101
|
+
.filter(it => it.text)
|
|
102
|
+
: [];
|
|
103
|
+
return items.map(it => {
|
|
104
|
+
const block = { type: 'text', text: it.text };
|
|
105
|
+
const ttl = it.tier === 'tier3' ? tier3Ttl : systemTtl;
|
|
106
|
+
if (ttl) block.cache_control = ttl;
|
|
107
|
+
return block;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
77
111
|
const MODELS = [
|
|
78
|
-
{ id: 'claude-opus-4-8', name: 'Claude Opus 4.8', provider: 'anthropic', contextWindow: 1000000 },
|
|
79
|
-
{ id: 'claude-opus-4-7', name: 'Claude Opus 4.7', provider: 'anthropic', contextWindow: 1000000 },
|
|
80
|
-
{ id: 'claude-opus-4-6', name: 'Claude Opus 4.6', provider: 'anthropic', contextWindow: 1000000 },
|
|
81
|
-
{ id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', provider: 'anthropic', contextWindow: 1000000 },
|
|
82
|
-
{ id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5', provider: 'anthropic', contextWindow: 200000 },
|
|
112
|
+
{ id: 'claude-opus-4-8', name: 'Claude Opus 4.8', provider: 'anthropic', family: 'opus', contextWindow: 1000000 },
|
|
113
|
+
{ id: 'claude-opus-4-7', name: 'Claude Opus 4.7', provider: 'anthropic', family: 'opus', contextWindow: 1000000 },
|
|
114
|
+
{ id: 'claude-opus-4-6', name: 'Claude Opus 4.6', provider: 'anthropic', family: 'opus', contextWindow: 1000000 },
|
|
115
|
+
{ id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', provider: 'anthropic', family: 'sonnet', contextWindow: 1000000 },
|
|
116
|
+
{ id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5', provider: 'anthropic', family: 'haiku', contextWindow: 200000 },
|
|
83
117
|
];
|
|
84
118
|
const ANTHROPIC_VERSION = '2023-06-01';
|
|
85
119
|
|
|
@@ -131,8 +165,21 @@ const EFFORT_BUDGET = {
|
|
|
131
165
|
low: 1024,
|
|
132
166
|
medium: 4096,
|
|
133
167
|
high: 16384,
|
|
168
|
+
xhigh: 32768,
|
|
134
169
|
max: 32768,
|
|
135
170
|
};
|
|
171
|
+
|
|
172
|
+
const MIN_THINKING_BUDGET = 1024;
|
|
173
|
+
const THINKING_OUTPUT_RESERVE = 1024;
|
|
174
|
+
|
|
175
|
+
function clampThinkingBudgetTokens(value, maxTokens) {
|
|
176
|
+
const desired = Math.floor(Number(value));
|
|
177
|
+
const max = Math.floor(Number(maxTokens));
|
|
178
|
+
if (!Number.isFinite(desired) || desired <= 0 || !Number.isFinite(max)) return null;
|
|
179
|
+
const ceiling = max - THINKING_OUTPUT_RESERVE;
|
|
180
|
+
if (ceiling < MIN_THINKING_BUDGET) return null;
|
|
181
|
+
return Math.max(MIN_THINKING_BUDGET, Math.min(desired, ceiling));
|
|
182
|
+
}
|
|
136
183
|
// Anthropic forbids oneOf / allOf / anyOf at the TOP level of input_schema.
|
|
137
184
|
// Mirror the same sanitizer as anthropic-oauth.mjs so both providers are safe.
|
|
138
185
|
function _sanitizeInputSchema(schema, toolName) {
|
|
@@ -169,9 +216,11 @@ function _sanitizeInputSchema(schema, toolName) {
|
|
|
169
216
|
if (addition) description = description ? `${description} ${addition}` : addition;
|
|
170
217
|
}
|
|
171
218
|
const mergedPropsCount = Object.keys(mergedProps).length;
|
|
172
|
-
process.
|
|
173
|
-
|
|
174
|
-
|
|
219
|
+
if (process.env.MIXDOG_DEBUG_SESSION_LOG) {
|
|
220
|
+
process.stderr.write(
|
|
221
|
+
`[anthropic-sanitizer] tool="${toolName ?? ''}" compound="${compoundKey}" branches=${Array.isArray(compound) ? compound.length : 0} mergedProps=${mergedPropsCount}\n`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
175
224
|
return {
|
|
176
225
|
type: 'object',
|
|
177
226
|
...(description ? { description } : {}),
|
|
@@ -180,11 +229,28 @@ function _sanitizeInputSchema(schema, toolName) {
|
|
|
180
229
|
}
|
|
181
230
|
|
|
182
231
|
function toAnthropicTools(tools) {
|
|
183
|
-
return tools.map((t) =>
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
232
|
+
return tools.map((t) => {
|
|
233
|
+
const out = {
|
|
234
|
+
name: t.name,
|
|
235
|
+
description: t.description,
|
|
236
|
+
input_schema: _sanitizeInputSchema(t.inputSchema, t.name),
|
|
237
|
+
};
|
|
238
|
+
if (t.deferLoading === true || t.defer_loading === true) out.defer_loading = true;
|
|
239
|
+
return out;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function nativeAnthropicTools(opts) {
|
|
243
|
+
return Array.isArray(opts?.nativeTools)
|
|
244
|
+
? opts.nativeTools.filter(t => t && typeof t === 'object')
|
|
245
|
+
: [];
|
|
246
|
+
}
|
|
247
|
+
function deferredAnthropicTools(activeTools, opts) {
|
|
248
|
+
if (opts?.session?.deferredNativeTools !== true) return [];
|
|
249
|
+
const active = new Set((activeTools || []).map((tool) => String(tool?.name || '').trim()).filter(Boolean));
|
|
250
|
+
const catalog = Array.isArray(opts.session.deferredToolCatalog) ? opts.session.deferredToolCatalog : [];
|
|
251
|
+
return catalog
|
|
252
|
+
.filter((tool) => tool?.name && !active.has(String(tool.name)))
|
|
253
|
+
.map((tool) => ({ ...tool, deferLoading: true }));
|
|
188
254
|
}
|
|
189
255
|
function toAnthropicMessages(messages) {
|
|
190
256
|
// Marker-free lowering. cache_control is applied AFTER sanitization by
|
|
@@ -218,10 +284,15 @@ function toAnthropicMessages(messages) {
|
|
|
218
284
|
}
|
|
219
285
|
if (m.role === 'tool') {
|
|
220
286
|
const last = result[result.length - 1];
|
|
287
|
+
const refs = Array.isArray(m.nativeToolSearch?.toolReferences)
|
|
288
|
+
? m.nativeToolSearch.toolReferences.map((name) => String(name || '').trim()).filter(Boolean)
|
|
289
|
+
: [];
|
|
221
290
|
const block = {
|
|
222
291
|
type: 'tool_result',
|
|
223
292
|
tool_use_id: m.toolCallId || '',
|
|
224
|
-
content:
|
|
293
|
+
content: refs.length
|
|
294
|
+
? refs.map((name) => ({ type: 'tool_reference', tool_name: name }))
|
|
295
|
+
: normalizeContentForAnthropic(m.content),
|
|
225
296
|
};
|
|
226
297
|
if (last?.role === 'user' && Array.isArray(last.content)) {
|
|
227
298
|
last.content.push(block);
|
|
@@ -241,17 +312,15 @@ function toAnthropicMessages(messages) {
|
|
|
241
312
|
// sanitizeAnthropicContentPairs has already run (and must NOT run again
|
|
242
313
|
// after this), the blocks we mark here are exactly the blocks the provider
|
|
243
314
|
// sees, so the cache breakpoint is stable across turns.
|
|
244
|
-
// tier3: the user message whose first text block / string content
|
|
245
|
-
// startsWith '<system-reminder>' AND includes BP3_SENTINEL —
|
|
246
|
-
// mark its last content block with tier3Ttl.
|
|
247
315
|
// message-anchor: prefer a safe tool_result tail, then a previous real user
|
|
248
316
|
// text turn if another slot remains. Synthetic
|
|
249
317
|
// <system-reminder> messages and current pure-text prompts
|
|
250
318
|
// are excluded so per-call volatileTail/current prompt
|
|
251
319
|
// content never becomes a 1h prefix key.
|
|
252
|
-
// messageTtl === null disables the tail
|
|
320
|
+
// messageTtl === null disables the tail. BP3 (tier3) now rides a system block,
|
|
321
|
+
// so it is no longer marked here.
|
|
253
322
|
// ANTHROPIC_MSG_SLOTS=0 is honoured upstream by passing messageTtl = null.
|
|
254
|
-
function applyAnthropicCacheMarkers(sanitizedMessages, { messageTtl = CACHE_TTL_VOLATILE, messageSlots = 1
|
|
323
|
+
function applyAnthropicCacheMarkers(sanitizedMessages, { messageTtl = CACHE_TTL_VOLATILE, messageSlots = 1 } = {}) {
|
|
255
324
|
if (!Array.isArray(sanitizedMessages) || sanitizedMessages.length === 0) {
|
|
256
325
|
return sanitizedMessages;
|
|
257
326
|
}
|
|
@@ -265,25 +334,20 @@ function applyAnthropicCacheMarkers(sanitizedMessages, { messageTtl = CACHE_TTL_
|
|
|
265
334
|
return '';
|
|
266
335
|
};
|
|
267
336
|
const isSystemReminder = (content) => firstText(content).startsWith('<system-reminder>');
|
|
268
|
-
const isTier3SystemReminder = (content) => {
|
|
269
|
-
const text = firstText(content);
|
|
270
|
-
return text.startsWith('<system-reminder>') && text.includes(BP3_SENTINEL);
|
|
271
|
-
};
|
|
272
337
|
|
|
273
338
|
const markLast = (msg, ttl) => {
|
|
274
339
|
if (!msg) return;
|
|
275
340
|
msg.content = appendCacheControl(msg.content, ttl);
|
|
276
341
|
};
|
|
277
342
|
const ttlRank = (ttl) => ttl?.ttl === '1h' ? 2 : 1;
|
|
278
|
-
const canMarkMessageIdx = (idx
|
|
343
|
+
const canMarkMessageIdx = (idx) => {
|
|
344
|
+
// System-reminder messages (volatileTail / roleSpecific BP4) vary
|
|
345
|
+
// per-call, so never pin them with a 1h marker. The 1h system blocks
|
|
346
|
+
// (BP1/BP2/BP3) already satisfy Anthropic's "1h before 5m" ordering.
|
|
279
347
|
if (idx < 0) return false;
|
|
280
348
|
const msg = sanitizedMessages[idx];
|
|
281
349
|
if (ttlRank(messageTtl) > ttlRank(CACHE_TTL_VOLATILE)
|
|
282
|
-
&& isSystemReminder(msg?.content)
|
|
283
|
-
&& !isTier3SystemReminder(msg?.content)) {
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
if (tier3Idx >= 0 && idx < tier3Idx && ttlRank(messageTtl) < ttlRank(tier3Ttl)) {
|
|
350
|
+
&& isSystemReminder(msg?.content)) {
|
|
287
351
|
return false;
|
|
288
352
|
}
|
|
289
353
|
return true;
|
|
@@ -312,29 +376,16 @@ function applyAnthropicCacheMarkers(sanitizedMessages, { messageTtl = CACHE_TTL_
|
|
|
312
376
|
return -1;
|
|
313
377
|
};
|
|
314
378
|
|
|
315
|
-
// tier3 — locate the sentinel-tagged system-reminder user message.
|
|
316
|
-
let tier3MsgIdx = -1;
|
|
317
|
-
if (tier3Ttl !== null) {
|
|
318
|
-
for (let i = 0; i < sanitizedMessages.length; i++) {
|
|
319
|
-
const m = sanitizedMessages[i];
|
|
320
|
-
if (m?.role === 'user' && isTier3SystemReminder(m.content)) {
|
|
321
|
-
tier3MsgIdx = i;
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (tier3MsgIdx >= 0) markLast(sanitizedMessages[tier3MsgIdx], tier3Ttl);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
379
|
if (messageTtl !== null) {
|
|
329
380
|
const slots = Math.max(0, Math.min(4, Number(messageSlots) || 0));
|
|
330
|
-
const marked = new Set(
|
|
381
|
+
const marked = new Set();
|
|
331
382
|
const candidates = [latestToolResultTailIdx(), previousUserTextAnchorIdx()];
|
|
332
383
|
for (const idx of candidates) {
|
|
333
384
|
if (slots <= 0) break;
|
|
334
|
-
if (idx < 0 || marked.has(idx) || !canMarkMessageIdx(idx
|
|
385
|
+
if (idx < 0 || marked.has(idx) || !canMarkMessageIdx(idx)) continue;
|
|
335
386
|
markLast(sanitizedMessages[idx], messageTtl);
|
|
336
387
|
marked.add(idx);
|
|
337
|
-
if (marked.size
|
|
388
|
+
if (marked.size >= slots) break;
|
|
338
389
|
}
|
|
339
390
|
}
|
|
340
391
|
|
|
@@ -352,7 +403,7 @@ export class AnthropicProvider {
|
|
|
352
403
|
constructor(config) {
|
|
353
404
|
this.config = config;
|
|
354
405
|
this.name = config.name || 'anthropic';
|
|
355
|
-
const betaHeaders = config.disableBetaHeaders ? null : buildAnthropicBetaHeaders();
|
|
406
|
+
const betaHeaders = config.disableBetaHeaders ? null : buildAnthropicBetaHeaders({ toolSearch: true });
|
|
356
407
|
this.client = new Anthropic({
|
|
357
408
|
apiKey: config.apiKey || process.env.ANTHROPIC_API_KEY,
|
|
358
409
|
...(config.baseURL ? { baseURL: config.baseURL } : {}),
|
|
@@ -366,7 +417,7 @@ export class AnthropicProvider {
|
|
|
366
417
|
const newKey = cfg?.apiKey || this.config.apiKey || (this.name === 'anthropic' ? process.env.ANTHROPIC_API_KEY : null);
|
|
367
418
|
if (newKey) {
|
|
368
419
|
this.config = { ...(this.config || {}), ...(cfg || {}), apiKey: newKey };
|
|
369
|
-
const betaHeaders = this.config.disableBetaHeaders ? null : buildAnthropicBetaHeaders();
|
|
420
|
+
const betaHeaders = this.config.disableBetaHeaders ? null : buildAnthropicBetaHeaders({ toolSearch: true });
|
|
370
421
|
this.client = new Anthropic({
|
|
371
422
|
apiKey: newKey,
|
|
372
423
|
...(this.config.baseURL ? { baseURL: this.config.baseURL } : {}),
|
|
@@ -402,17 +453,17 @@ export class AnthropicProvider {
|
|
|
402
453
|
|
|
403
454
|
const systemMsgs = messages.filter(m => m.role === 'system');
|
|
404
455
|
const chatMsgs = messages.filter(m => m.role !== 'system');
|
|
405
|
-
|
|
456
|
+
// BP1 baseRules + BP2 stableSystem at ttls.system; BP3 sessionMarker
|
|
457
|
+
// (cacheTier:'tier3') at ttls.tier3 — each its own system content block.
|
|
458
|
+
const systemBlocks = buildSystemBlocks(systemMsgs, ttls.system, ttls.tier3);
|
|
406
459
|
|
|
407
460
|
// 4-BP budget: aligned with anthropic-oauth. tools BP is dropped —
|
|
408
461
|
// system BP covers the tools prefix via Anthropic prefix semantics
|
|
409
462
|
// (order: tools → system → messages). That frees 1 slot for
|
|
410
463
|
// messages-tail.
|
|
411
464
|
const toolsBpUsed = 0;
|
|
412
|
-
const systemBpUsed =
|
|
413
|
-
const
|
|
414
|
-
const tier3BpUsed = tier3Idx >= 0 ? 1 : 0;
|
|
415
|
-
const usedSlots = toolsBpUsed + systemBpUsed + tier3BpUsed;
|
|
465
|
+
const systemBpUsed = systemBlocks.filter(b => b.cache_control).length;
|
|
466
|
+
const usedSlots = toolsBpUsed + systemBpUsed;
|
|
416
467
|
// Env override for BP strategy. ANTHROPIC_MSG_SLOTS=0 disables
|
|
417
468
|
// message caching entirely. Any value >=1 first marks the previous
|
|
418
469
|
// user text turn; a second free slot marks the tail. Mirrors
|
|
@@ -428,34 +479,32 @@ export class AnthropicProvider {
|
|
|
428
479
|
// or delete a marked block. NEVER sanitize again after this.
|
|
429
480
|
// msgSlots === 0 → message-tail disabled.
|
|
430
481
|
const tailTtl = msgSlots > 0 ? ttls.messages : null;
|
|
431
|
-
const tier3Ttl = tier3Idx >= 0 ? ttls.tier3 : null;
|
|
432
482
|
const anthropicMessages = applyAnthropicCacheMarkers(
|
|
433
483
|
toAnthropicMessages(chatMsgs),
|
|
434
|
-
{ messageTtl: tailTtl, messageSlots: msgSlots
|
|
484
|
+
{ messageTtl: tailTtl, messageSlots: msgSlots },
|
|
435
485
|
);
|
|
436
486
|
|
|
437
487
|
const params = {
|
|
438
488
|
model: useModel,
|
|
439
489
|
max_tokens: maxTokens,
|
|
440
|
-
system:
|
|
441
|
-
? [ttls.system
|
|
442
|
-
? { type: 'text', text: systemText, cache_control: ttls.system }
|
|
443
|
-
: { type: 'text', text: systemText }]
|
|
444
|
-
: undefined,
|
|
490
|
+
system: systemBlocks.length ? systemBlocks : undefined,
|
|
445
491
|
messages: anthropicMessages,
|
|
446
492
|
};
|
|
447
|
-
|
|
493
|
+
const nativeTools = nativeAnthropicTools(opts);
|
|
494
|
+
if (tools?.length || nativeTools.length) {
|
|
448
495
|
// No cache_control on tools — the system BP covers tools via
|
|
449
496
|
// Anthropic prefix semantics (order: tools → system → messages).
|
|
450
|
-
params.tools = toAnthropicTools(tools);
|
|
497
|
+
params.tools = [...nativeTools, ...toAnthropicTools([...(tools || []), ...deferredAnthropicTools(tools || [], opts)])];
|
|
451
498
|
}
|
|
452
499
|
// Effort → extended thinking budget. Gateway inherit mode may pass the
|
|
453
|
-
// exact
|
|
500
|
+
// exact OAuth client budget from the incoming Anthropic request.
|
|
454
501
|
const thinkingBudgetTokens = Number(opts.thinkingBudgetTokens);
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
502
|
+
const requestedThinkingBudget = Number.isFinite(thinkingBudgetTokens) && thinkingBudgetTokens > 0
|
|
503
|
+
? thinkingBudgetTokens
|
|
504
|
+
: (opts.effort && EFFORT_BUDGET[opts.effort] ? EFFORT_BUDGET[opts.effort] : null);
|
|
505
|
+
const budgetTokens = clampThinkingBudgetTokens(requestedThinkingBudget, maxTokens);
|
|
506
|
+
if (budgetTokens) {
|
|
507
|
+
params.thinking = { type: 'enabled', budget_tokens: budgetTokens };
|
|
459
508
|
}
|
|
460
509
|
// Fast mode → speed: "fast" on models Anthropic marks as speed-capable.
|
|
461
510
|
if (opts.fast === true && supportsAnthropicFastMode(useModel)) {
|
|
@@ -479,7 +528,7 @@ export class AnthropicProvider {
|
|
|
479
528
|
// emitting SSE deltas must not be killed by a fixed total-lifetime timer.
|
|
480
529
|
// Mirrors the OAuth provider (Option A). Bounded instead by the
|
|
481
530
|
// per-attempt first-byte/HTTP-response timeout, the SSE idle watchdog,
|
|
482
|
-
// the
|
|
531
|
+
// the agent stall watchdog, and externalSignal (client disconnect /
|
|
483
532
|
// replaced-by-newer-request). totalSignal is a pure pass-through.
|
|
484
533
|
const externalSignal = opts.signal || null;
|
|
485
534
|
const totalTimeout = createPassthroughSignal(externalSignal);
|
|
@@ -493,10 +542,11 @@ export class AnthropicProvider {
|
|
|
493
542
|
const betaHeaders = {
|
|
494
543
|
'anthropic-beta': buildAnthropicBetaHeaders({
|
|
495
544
|
fastMode: this.fastModeBetaHeaderLatched,
|
|
545
|
+
toolSearch: true,
|
|
496
546
|
}),
|
|
497
547
|
};
|
|
498
548
|
|
|
499
|
-
const MAX_MIDSTREAM_RETRIES =
|
|
549
|
+
const MAX_MIDSTREAM_RETRIES = ANTHROPIC_MAX_MIDSTREAM_RETRIES;
|
|
500
550
|
let firstAttemptError = null;
|
|
501
551
|
let firstAttemptClassifier = null;
|
|
502
552
|
|
|
@@ -510,7 +560,7 @@ export class AnthropicProvider {
|
|
|
510
560
|
const liveModel = parseResult.model || useModel;
|
|
511
561
|
|
|
512
562
|
if (usageRaw || input || output || cacheRead || cacheWrite) {
|
|
513
|
-
|
|
563
|
+
traceAgentUsage({
|
|
514
564
|
sessionId: opts.sessionId || opts.session?.id || null,
|
|
515
565
|
iteration: Number.isFinite(Number(opts.iteration)) ? Number(opts.iteration) : null,
|
|
516
566
|
inputTokens: input,
|
|
@@ -694,6 +744,7 @@ export class AnthropicProvider {
|
|
|
694
744
|
`[${this.name}] empty stream (no message_start) — retry ${attemptIndex + 1}/${MAX_MIDSTREAM_RETRIES}\n`,
|
|
695
745
|
);
|
|
696
746
|
} catch {}
|
|
747
|
+
await _midstreamSleepWithAbort(midstreamBackoffFor(attemptIndex + 1), totalSignal);
|
|
697
748
|
continue;
|
|
698
749
|
}
|
|
699
750
|
if ((err?.truncatedStream === true || err?.code === 'TRUNCATED_STREAM')
|
|
@@ -708,6 +759,7 @@ export class AnthropicProvider {
|
|
|
708
759
|
`[${this.name}] truncated stream — retry ${attemptIndex + 1}/${MAX_MIDSTREAM_RETRIES}\n`,
|
|
709
760
|
);
|
|
710
761
|
} catch {}
|
|
762
|
+
await _midstreamSleepWithAbort(midstreamBackoffFor(attemptIndex + 1), totalSignal);
|
|
711
763
|
continue;
|
|
712
764
|
}
|
|
713
765
|
const classifier = _classifyMidstreamError(err, midState);
|
|
@@ -720,6 +772,7 @@ export class AnthropicProvider {
|
|
|
720
772
|
`[${this.name}] mid-stream recovered: retry ${attemptIndex + 1}/${MAX_MIDSTREAM_RETRIES} (cause: ${classifier})\n`,
|
|
721
773
|
);
|
|
722
774
|
} catch {}
|
|
775
|
+
await _midstreamSleepWithAbort(midstreamBackoffFor(attemptIndex + 1), totalSignal);
|
|
723
776
|
continue;
|
|
724
777
|
}
|
|
725
778
|
if (attemptIndex > 0 && firstAttemptError) {
|