mixdog 0.9.1 → 0.9.2
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 +8 -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/background-task-meta-smoke.mjs +1 -1
- package/scripts/bench-run.mjs +262 -0
- package/scripts/compact-smoke.mjs +12 -0
- package/scripts/compact-trigger-migration-smoke.mjs +67 -1
- 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/provider-stream-stall-test.mjs +276 -0
- package/scripts/provider-toolcall-test.mjs +599 -1
- 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 +306 -66
- package/scripts/toolcall-args-test.mjs +81 -0
- package/src/agents/debugger/AGENT.md +4 -4
- package/src/agents/heavy-worker/AGENT.md +4 -2
- package/src/agents/reviewer/AGENT.md +4 -4
- package/src/agents/worker/AGENT.md +4 -2
- 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 +710 -318
- 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 +12 -2
- package/src/rules/agent/00-common.md +7 -5
- package/src/rules/agent/30-explorer.md +7 -8
- package/src/rules/lead/01-general.md +3 -1
- package/src/rules/lead/lead-tool.md +7 -0
- package/src/rules/shared/01-tool.md +17 -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 +131 -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 +94 -16
- 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-oauth.mjs +332 -57
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +59 -32
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +27 -20
- 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/model-catalog.mjs +18 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +210 -21
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +78 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +202 -98
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +183 -20
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +15 -9
- 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.mjs +394 -132
- package/src/runtime/agent/orchestrator/session/manager.mjs +217 -170
- 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 +0 -0
- 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-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 +13 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +18 -2
- 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 +59 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4076 -3985
- package/src/runtime/agent/orchestrator/tools/patch.mjs +116 -2
- package/src/runtime/channels/backends/discord.mjs +99 -9
- package/src/runtime/channels/backends/telegram.mjs +501 -0
- package/src/runtime/channels/index.mjs +441 -1224
- package/src/runtime/channels/lib/config.mjs +54 -2
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/output-forwarder.mjs +80 -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 +283 -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/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +184 -19
- package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
- package/src/runtime/memory/lib/core-memory-store.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2.mjs +9 -6
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory.mjs +101 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- 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 +6 -3
- 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/tool-surface.mjs +98 -13
- package/src/runtime/shared/transcript-writer.mjs +129 -0
- package/src/runtime/shared/update-checker.mjs +214 -0
- package/src/standalone/agent-tool.mjs +255 -109
- package/src/standalone/channel-admin.mjs +133 -40
- package/src/standalone/channel-worker.mjs +8 -291
- package/src/standalone/explore-tool.mjs +2 -2
- package/src/standalone/memory-runtime-proxy.mjs +3 -1
- package/src/standalone/provider-admin.mjs +11 -0
- package/src/standalone/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2096 -732
- 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 +83 -7
- 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 +170 -98
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +159 -21
- 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 +6965 -2391
- package/src/tui/engine.mjs +287 -126
- package/src/tui/index.jsx +117 -7
- package/src/tui/keyboard-protocol.mjs +42 -0
- package/src/tui/lib/voice-recorder.mjs +453 -0
- package/src/tui/markdown/format-token.mjs +129 -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 +0 -11
- 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 +81 -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 +26 -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 +39 -12
- package/src/workflows/sequential/WORKFLOW.md +46 -0
- package/src/workflows/solo/WORKFLOW.md +7 -0
- 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
|
@@ -66,7 +66,7 @@ function codePointTokenWeight(cp) {
|
|
|
66
66
|
// surrogate-pair emoji are scored once, at the high emoji weight), takes the
|
|
67
67
|
// max of the weighted sum and the chars/4 ASCII floor, then applies the safety
|
|
68
68
|
// multiplier. Always overcounts relative to chars/4 for non-ASCII text.
|
|
69
|
-
function estimateTokens(text) {
|
|
69
|
+
export function estimateTokens(text) {
|
|
70
70
|
const s = String(text ?? '');
|
|
71
71
|
if (s.length === 0) return 0;
|
|
72
72
|
let weighted = 0;
|
|
@@ -74,7 +74,7 @@ function estimateTokens(text) {
|
|
|
74
74
|
const asciiFloor = s.length / 4; // never below the legacy chars/4 lower bound
|
|
75
75
|
return Math.ceil(Math.max(weighted, asciiFloor) * TOKEN_ESTIMATE_SAFETY_MULTIPLIER);
|
|
76
76
|
}
|
|
77
|
-
function messageEstimateText(m) {
|
|
77
|
+
export function messageEstimateText(m) {
|
|
78
78
|
if (!m || typeof m !== 'object') return '';
|
|
79
79
|
let text = typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? '');
|
|
80
80
|
if (m.role === 'assistant' && Array.isArray(m.toolCalls) && m.toolCalls.length) {
|
|
@@ -84,13 +84,260 @@ function messageEstimateText(m) {
|
|
|
84
84
|
if (m.role === 'tool' && m.toolCallId) text += `\n${m.toolCallId}`;
|
|
85
85
|
return text;
|
|
86
86
|
}
|
|
87
|
-
function estimateMessageTokens(m) {
|
|
87
|
+
export function estimateMessageTokens(m) {
|
|
88
88
|
return estimateTokens(messageEstimateText(m)) + 4;
|
|
89
89
|
}
|
|
90
90
|
export function estimateMessagesTokens(messages) {
|
|
91
91
|
return messages.reduce((sum, m) => sum + estimateMessageTokens(m), 0);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
export const DEFAULT_COMPACTION_BUFFER_TOKENS = 0;
|
|
95
|
+
export const DEFAULT_COMPACTION_BUFFER_RATIO = 0.1;
|
|
96
|
+
export const MAX_COMPACTION_BUFFER_RATIO = 0.25;
|
|
97
|
+
export const DEFAULT_COMPACTION_KEEP_TOKENS = 8_000;
|
|
98
|
+
const LEGACY_DEFAULT_COMPACTION_BUFFER_RATIO = 0.1;
|
|
99
|
+
|
|
100
|
+
export function positiveTokenInt(value) {
|
|
101
|
+
const n = Number(value);
|
|
102
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function envTokenInt(name) {
|
|
106
|
+
return positiveTokenInt(process.env[name]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function normalizeCompactionBufferRatio(value, fallback = DEFAULT_COMPACTION_BUFFER_RATIO) {
|
|
110
|
+
const n = Number(value);
|
|
111
|
+
if (Number.isFinite(n) && n > 0) return n > 1 ? n / 100 : n;
|
|
112
|
+
return fallback;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Percent-named inputs (bufferPercent / bufferPct / *_BUFFER_PERCENT) carry a
|
|
116
|
+
// PERCENT: 1 means 1% (0.01). Ratio-named inputs (bufferRatio / bufferFraction)
|
|
117
|
+
// carry a fraction: 0.01 means 1%, and a legacy value > 1 is read as a percent.
|
|
118
|
+
export function resolveBufferRatioCandidate(percentInputs = [], ratioInputs = []) {
|
|
119
|
+
for (const raw of percentInputs) {
|
|
120
|
+
const n = Number(raw);
|
|
121
|
+
if (Number.isFinite(n) && n > 0) return Math.min(1, n / 100);
|
|
122
|
+
}
|
|
123
|
+
for (const raw of ratioInputs) {
|
|
124
|
+
const n = Number(raw);
|
|
125
|
+
if (Number.isFinite(n) && n > 0) return n > 1 ? n / 100 : n;
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function resolveCompactBufferRatio(cfg = {}) {
|
|
131
|
+
const resolved = resolveBufferRatioCandidate(
|
|
132
|
+
[cfg.bufferPercent, cfg.bufferPct, process.env.MIXDOG_AGENT_COMPACT_BUFFER_PERCENT],
|
|
133
|
+
[cfg.bufferRatio, cfg.bufferFraction, process.env.MIXDOG_AGENT_COMPACT_BUFFER_RATIO],
|
|
134
|
+
);
|
|
135
|
+
return normalizeCompactionBufferRatio(resolved, DEFAULT_COMPACTION_BUFFER_RATIO);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function compactionBufferTokensForBoundary(boundaryTokens, opts = {}) {
|
|
139
|
+
const boundary = Math.max(0, Math.floor(Number(boundaryTokens) || 0));
|
|
140
|
+
const explicit = Math.max(0, Math.floor(Number(opts.explicitTokens) || 0));
|
|
141
|
+
if (!boundary) return explicit;
|
|
142
|
+
const maxRatio = normalizeCompactionBufferRatio(opts.maxRatio, MAX_COMPACTION_BUFFER_RATIO);
|
|
143
|
+
const cap = Math.max(0, Math.floor(boundary * maxRatio));
|
|
144
|
+
if (explicit > 0) return Math.max(0, Math.min(explicit, cap));
|
|
145
|
+
const ratio = normalizeCompactionBufferRatio(opts.ratio, DEFAULT_COMPACTION_BUFFER_RATIO);
|
|
146
|
+
return Math.max(0, Math.min(Math.floor(boundary * ratio), cap));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function isPersistedZeroBufferTelemetry(cfg = {}, boundaryTokens = 0) {
|
|
150
|
+
const boundary = positiveTokenInt(boundaryTokens);
|
|
151
|
+
if (!boundary) return false;
|
|
152
|
+
if (envTokenInt('MIXDOG_AGENT_COMPACT_BUFFER_TOKENS')) return false;
|
|
153
|
+
for (const envName of ['MIXDOG_AGENT_COMPACT_BUFFER_PERCENT', 'MIXDOG_AGENT_COMPACT_BUFFER_RATIO']) {
|
|
154
|
+
const n = Number(process.env[envName]);
|
|
155
|
+
if (Number.isFinite(n) && n > 0) return false;
|
|
156
|
+
}
|
|
157
|
+
for (const key of ['bufferPercent', 'bufferPct', 'bufferFraction']) {
|
|
158
|
+
const n = Number(cfg?.[key]);
|
|
159
|
+
if (Number.isFinite(n) && n > 0) return false;
|
|
160
|
+
}
|
|
161
|
+
const ratio = Number(cfg?.bufferRatio);
|
|
162
|
+
if (Number.isFinite(ratio) && ratio > 0) return false;
|
|
163
|
+
const explicitTokens = Number(cfg?.bufferTokens ?? cfg?.buffer);
|
|
164
|
+
if (!Number.isFinite(explicitTokens) || explicitTokens !== 0) return false;
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function isLegacyDefaultBufferTelemetry(cfg = {}, boundaryTokens = 0) {
|
|
169
|
+
const boundary = positiveTokenInt(boundaryTokens);
|
|
170
|
+
if (!boundary) return false;
|
|
171
|
+
if (envTokenInt('MIXDOG_AGENT_COMPACT_BUFFER_TOKENS')) return false;
|
|
172
|
+
for (const envName of ['MIXDOG_AGENT_COMPACT_BUFFER_PERCENT', 'MIXDOG_AGENT_COMPACT_BUFFER_RATIO']) {
|
|
173
|
+
const n = Number(process.env[envName]);
|
|
174
|
+
if (Number.isFinite(n) && n > 0) return false;
|
|
175
|
+
}
|
|
176
|
+
// Percent/fraction-named fields are operator config. Legacy/default
|
|
177
|
+
// telemetry persisted bufferTokens + bufferRatio after a check/compact pass.
|
|
178
|
+
for (const key of ['bufferPercent', 'bufferPct', 'bufferFraction']) {
|
|
179
|
+
const n = Number(cfg?.[key]);
|
|
180
|
+
if (Number.isFinite(n) && n > 0) return false;
|
|
181
|
+
}
|
|
182
|
+
const explicitTokens = positiveTokenInt(cfg?.bufferTokens ?? cfg?.buffer);
|
|
183
|
+
const ratio = Number(cfg?.bufferRatio);
|
|
184
|
+
if (!explicitTokens || !Number.isFinite(ratio) || Math.abs(ratio - LEGACY_DEFAULT_COMPACTION_BUFFER_RATIO) > 1e-9) return false;
|
|
185
|
+
const expectedTokens = Math.floor(boundary * LEGACY_DEFAULT_COMPACTION_BUFFER_RATIO);
|
|
186
|
+
const cfgBoundary = positiveTokenInt(cfg?.boundaryTokens);
|
|
187
|
+
const cfgTrigger = positiveTokenInt(cfg?.triggerTokens);
|
|
188
|
+
return explicitTokens === expectedTokens
|
|
189
|
+
|| (cfgBoundary === boundary && cfgTrigger > 0 && explicitTokens === Math.max(0, boundary - cfgTrigger));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function compactBufferConfigForBoundary(cfg = {}, boundaryTokens = 0) {
|
|
193
|
+
const base = cfg || {};
|
|
194
|
+
if (!isLegacyDefaultBufferTelemetry(base, boundaryTokens)
|
|
195
|
+
&& !isPersistedZeroBufferTelemetry(base, boundaryTokens)) {
|
|
196
|
+
return base;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
...base,
|
|
200
|
+
bufferTokens: null,
|
|
201
|
+
buffer: null,
|
|
202
|
+
bufferRatio: null,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function resolveCompactBufferTokens(boundaryTokens, cfg = {}, opts = {}) {
|
|
207
|
+
const boundary = positiveTokenInt(boundaryTokens);
|
|
208
|
+
const effectiveCfg = compactBufferConfigForBoundary(cfg, boundary);
|
|
209
|
+
const configured = positiveTokenInt(effectiveCfg.bufferTokens ?? effectiveCfg.buffer)
|
|
210
|
+
|| envTokenInt('MIXDOG_AGENT_COMPACT_BUFFER_TOKENS')
|
|
211
|
+
|| 0;
|
|
212
|
+
if (!boundary) return configured || positiveTokenInt(opts.defaultTokens) || DEFAULT_COMPACTION_BUFFER_TOKENS;
|
|
213
|
+
return compactionBufferTokensForBoundary(boundary, {
|
|
214
|
+
explicitTokens: configured,
|
|
215
|
+
ratio: resolveCompactBufferRatio(effectiveCfg),
|
|
216
|
+
maxRatio: opts.maxRatio ?? MAX_COMPACTION_BUFFER_RATIO,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function resolveCompactTriggerTokens(sessionOrConfig = {}, boundaryTokens = 0) {
|
|
221
|
+
const boundary = positiveTokenInt(boundaryTokens);
|
|
222
|
+
if (!boundary) return null;
|
|
223
|
+
const cfg = sessionOrConfig?.compaction || sessionOrConfig || {};
|
|
224
|
+
const autoLimit = positiveTokenInt(sessionOrConfig?.autoCompactTokenLimit ?? cfg?.autoCompactTokenLimit);
|
|
225
|
+
if (autoLimit && autoLimit < boundary) return Math.max(1, autoLimit);
|
|
226
|
+
const buffer = resolveCompactBufferTokens(boundary, cfg);
|
|
227
|
+
return Math.max(1, boundary - buffer);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function stripSystemReminder(text) {
|
|
231
|
+
return String(text || '')
|
|
232
|
+
.replace(/^\s*<system-reminder>\s*/i, '')
|
|
233
|
+
.replace(/\s*<\/system-reminder>\s*$/i, '')
|
|
234
|
+
.trim();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function splitMarkdownSections(text) {
|
|
238
|
+
const sections = [];
|
|
239
|
+
let current = [];
|
|
240
|
+
for (const line of String(text || '').split(/\r?\n/)) {
|
|
241
|
+
if (/^#\s+/.test(line) && current.length) {
|
|
242
|
+
const body = current.join('\n').trim();
|
|
243
|
+
if (body) sections.push(body);
|
|
244
|
+
current = [line];
|
|
245
|
+
} else {
|
|
246
|
+
current.push(line);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const tail = current.join('\n').trim();
|
|
250
|
+
if (tail) sections.push(tail);
|
|
251
|
+
return sections;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function reminderSectionBucket(section) {
|
|
255
|
+
const heading = String(section.match(/^#\s+([^\n]+)/)?.[1] || '').trim().toLowerCase();
|
|
256
|
+
if (heading.includes('core memory')) return 'memory';
|
|
257
|
+
if (heading.includes('active workflow') || heading.includes('available agents') || heading.includes('workflow')) return 'workflow';
|
|
258
|
+
if (heading.includes('workspace')) return 'workspace';
|
|
259
|
+
if (heading.includes('environment')) return 'environment';
|
|
260
|
+
return 'other';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function summarizeContextMessages(messages) {
|
|
264
|
+
const rows = {
|
|
265
|
+
system: { count: 0, tokens: 0 },
|
|
266
|
+
user: { count: 0, tokens: 0 },
|
|
267
|
+
assistant: { count: 0, tokens: 0 },
|
|
268
|
+
tool: { count: 0, tokens: 0 },
|
|
269
|
+
other: { count: 0, tokens: 0 },
|
|
270
|
+
};
|
|
271
|
+
const semantic = {
|
|
272
|
+
system: { count: 0, tokens: 0 },
|
|
273
|
+
chat: { count: 0, tokens: 0 },
|
|
274
|
+
assistant: { count: 0, tokens: 0 },
|
|
275
|
+
toolResults: { count: 0, tokens: 0 },
|
|
276
|
+
reminders: { count: 0, tokens: 0, otherTokens: 0 },
|
|
277
|
+
workflow: { tokens: 0 },
|
|
278
|
+
memory: { tokens: 0 },
|
|
279
|
+
workspace: { tokens: 0 },
|
|
280
|
+
environment: { tokens: 0 },
|
|
281
|
+
other: { tokens: 0 },
|
|
282
|
+
};
|
|
283
|
+
let toolCallCount = 0;
|
|
284
|
+
let toolCallTokens = 0;
|
|
285
|
+
let toolResultCount = 0;
|
|
286
|
+
let toolResultTokens = 0;
|
|
287
|
+
for (const message of messages || []) {
|
|
288
|
+
const role = rows[message?.role] ? message.role : 'other';
|
|
289
|
+
const text = messageEstimateText(message);
|
|
290
|
+
const tokens = estimateMessageTokens(message);
|
|
291
|
+
rows[role].count += 1;
|
|
292
|
+
rows[role].tokens += tokens;
|
|
293
|
+
if (role === 'system') {
|
|
294
|
+
semantic.system.count += 1;
|
|
295
|
+
semantic.system.tokens += tokens;
|
|
296
|
+
} else if (role === 'user') {
|
|
297
|
+
if (String(text || '').trim().startsWith('<system-reminder>')) {
|
|
298
|
+
semantic.reminders.count += 1;
|
|
299
|
+
semantic.reminders.tokens += tokens;
|
|
300
|
+
let sectionTokens = 0;
|
|
301
|
+
for (const section of splitMarkdownSections(stripSystemReminder(text))) {
|
|
302
|
+
const bucket = reminderSectionBucket(section);
|
|
303
|
+
const sectionTokenCount = estimateTokens(section);
|
|
304
|
+
semantic[bucket].tokens += sectionTokenCount;
|
|
305
|
+
sectionTokens += sectionTokenCount;
|
|
306
|
+
}
|
|
307
|
+
semantic.reminders.otherTokens += Math.max(0, tokens - sectionTokens);
|
|
308
|
+
} else {
|
|
309
|
+
semantic.chat.count += 1;
|
|
310
|
+
semantic.chat.tokens += tokens;
|
|
311
|
+
}
|
|
312
|
+
} else if (role === 'assistant') {
|
|
313
|
+
semantic.assistant.count += 1;
|
|
314
|
+
semantic.assistant.tokens += tokens;
|
|
315
|
+
} else if (role === 'tool') {
|
|
316
|
+
semantic.toolResults.count += 1;
|
|
317
|
+
semantic.toolResults.tokens += tokens;
|
|
318
|
+
}
|
|
319
|
+
if (message?.role === 'assistant' && Array.isArray(message.toolCalls) && message.toolCalls.length) {
|
|
320
|
+
toolCallCount += message.toolCalls.length;
|
|
321
|
+
try { toolCallTokens += estimateTokens(JSON.stringify(message.toolCalls)); }
|
|
322
|
+
catch { toolCallTokens += estimateTokens(`[${message.toolCalls.length} tool calls]`); }
|
|
323
|
+
}
|
|
324
|
+
if (message?.role === 'tool') {
|
|
325
|
+
toolResultCount += 1;
|
|
326
|
+
toolResultTokens += tokens;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
count: Array.isArray(messages) ? messages.length : 0,
|
|
331
|
+
estimatedTokens: Array.isArray(messages) ? estimateMessagesTokens(messages) : 0,
|
|
332
|
+
roles: rows,
|
|
333
|
+
semantic,
|
|
334
|
+
toolCallCount,
|
|
335
|
+
toolCallTokens,
|
|
336
|
+
toolResultCount,
|
|
337
|
+
toolResultTokens,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
94
341
|
// Per-request overhead the provider injects that never appears in the
|
|
95
342
|
// `messages` array: function-calling preamble + system-prompt framing the
|
|
96
343
|
// provider wraps around the request. The chars/4 message estimate misses all
|