mixdog 1.2.1 → 1.2.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 +1 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +1 -0
- package/src/repl/slash-commands.mjs +16 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +77 -17
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
- package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +56 -23
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +31 -20
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +41 -21
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/memory/lib/pg/process.mjs +34 -24
- package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
- package/src/runtime/office/README.md +1 -1
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/err-text.mjs +25 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +123 -134
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -40
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/turn-changes.mjs +447 -219
- package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
- package/src/runtime/shared/turn-snapshot.mjs +170 -48
- package/src/runtime/shared/turn-worktree-snapshot.mjs +135 -46
- package/src/runtime/shared/worktrees/contract.mjs +0 -24
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/session-runtime/boot/apis.mjs +6 -0
- package/src/session-runtime/boot/infrastructure.mjs +6 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/connect.mjs +29 -9
- package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
- package/src/session-runtime/mcp-glue.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +174 -0
- package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
- package/src/session-runtime/model-route/set-route.mjs +83 -15
- package/src/session-runtime/model-route/web-search-route.mjs +1 -1
- package/src/session-runtime/native-web-search/routes.mjs +22 -3
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
- package/src/session-runtime/quick-web-search-models.mjs +13 -38
- package/src/session-runtime/resource-extension-sync.mjs +4 -0
- package/src/session-runtime/resource-mcp-api.mjs +98 -2
- package/src/session-runtime/runtime-review-api.mjs +13 -0
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
- package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-telemetry.mjs +55 -0
- package/src/standalone/daemon.mjs +3 -7
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
- package/src/standalone/session-service/agent-tree.mjs +12 -0
- package/src/standalone/session-service/quota-resume.mjs +8 -0
- package/src/standalone/session-service/retention/busy.mjs +15 -1
- package/src/standalone/session-service-api.mjs +5 -0
- package/src/standalone/session-service.mjs +1 -0
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/create-app-pickers.mjs +4 -0
- package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
- package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +11 -16
- package/src/tui/app/slash-commands.mjs +7 -2
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/status-line/local-line.mjs +5 -2
- package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
- package/src/tui/dist/index.mjs +816 -43
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +33 -24
- package/src/tui/session/session-api/extensions.mjs +22 -0
- package/src/tui/session/session-api/integrations.mjs +7 -0
- package/src/tui/session/session-api/lifecycle.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +5 -14
- package/src/tui/session/session-flow/drain.mjs +7 -1
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/turn.mjs +38 -15
- package/src/tui/statusline-ansi-bridge.mjs +1 -1
- package/src/ui/statusline-agents.mjs +15 -4
- package/src/ui/statusline.mjs +7 -3
- package/src/ui/streaming-markdown-heal.mjs +34 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
package/src/ui/statusline.mjs
CHANGED
|
@@ -197,6 +197,7 @@ export async function renderStatusline({
|
|
|
197
197
|
model = '',
|
|
198
198
|
effort = '',
|
|
199
199
|
fast = false,
|
|
200
|
+
ultra = false,
|
|
200
201
|
cwd = '',
|
|
201
202
|
stats,
|
|
202
203
|
sessionId,
|
|
@@ -223,6 +224,7 @@ export async function renderStatusline({
|
|
|
223
224
|
model,
|
|
224
225
|
effort,
|
|
225
226
|
fast,
|
|
227
|
+
ultra,
|
|
226
228
|
cwd,
|
|
227
229
|
stats,
|
|
228
230
|
sessionId,
|
|
@@ -233,7 +235,7 @@ export async function renderStatusline({
|
|
|
233
235
|
...displayArgs,
|
|
234
236
|
});
|
|
235
237
|
} catch {
|
|
236
|
-
return fallbackLine({ provider, model, effort, fast, cwd, stats, ...displayArgs });
|
|
238
|
+
return fallbackLine({ provider, model, effort, fast, ultra, cwd, stats, ...displayArgs });
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
|
|
@@ -244,6 +246,7 @@ function renderNativeStatusline({
|
|
|
244
246
|
model = '',
|
|
245
247
|
effort = '',
|
|
246
248
|
fast = false,
|
|
249
|
+
ultra = false,
|
|
247
250
|
stats,
|
|
248
251
|
sessionId,
|
|
249
252
|
contextWindow = 0,
|
|
@@ -275,7 +278,7 @@ function renderNativeStatusline({
|
|
|
275
278
|
|
|
276
279
|
const sep = ` ${D}│${R} `;
|
|
277
280
|
const l1Parts = [
|
|
278
|
-
formatModelSegment({ provider, model, effort, fast, cols }),
|
|
281
|
+
formatModelSegment({ provider, model, effort, fast, ultra, cols }),
|
|
279
282
|
formatContextSegment(ctxPct, cols, s.currentContextSource),
|
|
280
283
|
...quotaSegmentsFor({ provider, model, effort, fast, sessionId, clientHostPid, gatewayStatus, cols }),
|
|
281
284
|
].filter(Boolean);
|
|
@@ -664,6 +667,7 @@ function fallbackLine({
|
|
|
664
667
|
model = '',
|
|
665
668
|
effort = '',
|
|
666
669
|
fast = false,
|
|
670
|
+
ultra = false,
|
|
667
671
|
cwd: _cwd = '',
|
|
668
672
|
stats,
|
|
669
673
|
contextWindow = 0,
|
|
@@ -687,7 +691,7 @@ function fallbackLine({
|
|
|
687
691
|
});
|
|
688
692
|
const sep = ` ${D}│${R} `;
|
|
689
693
|
const parts = [
|
|
690
|
-
formatModelSegment({ provider, model, effort, fast, cols }),
|
|
694
|
+
formatModelSegment({ provider, model, effort, fast, ultra, cols }),
|
|
691
695
|
formatContextSegment(ctxPct, cols, s.currentContextSource),
|
|
692
696
|
].filter(Boolean);
|
|
693
697
|
if (!parts.length) return statusSubtle('> mixdog');
|
|
@@ -213,12 +213,43 @@ function healIncompleteLink(text, isPendingLocalPath) {
|
|
|
213
213
|
return `${prefix}[${closeEmphasis(caption)}${']'.repeat(Math.max(0, depth - 1))}]()`;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
const PIPE_ROW = /^ {0,3}\|/;
|
|
217
|
+
const DELIMITER_ROW = /^ {0,3}\|?\s*:?-+:?\s*(?:\|\s*:?-+:?\s*)*\|?\s*$/;
|
|
218
|
+
const PARTIAL_DELIMITER_ROW = /^ {0,3}\|?[\s:|-]*$/;
|
|
219
|
+
|
|
220
|
+
function tableCells(line) {
|
|
221
|
+
const cells = line.trim().split(/(?<!\\)\|/);
|
|
222
|
+
if (cells[0].trim() === '') cells.shift();
|
|
223
|
+
if (cells.length && cells[cells.length - 1].trim() === '') cells.pop();
|
|
224
|
+
return cells.length;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// A table streams in as its header row, then its delimiter row a token at a
|
|
228
|
+
// time. Until the delimiter is complete (and has the header's cell count) the
|
|
229
|
+
// rows are a paragraph of raw pipes, which then re-laid out as a table of a
|
|
230
|
+
// different height — the reply grew and shrank under a followed transcript.
|
|
231
|
+
// Hold both rows back until the table can form in one step.
|
|
232
|
+
function trimPendingTableHead(text) {
|
|
233
|
+
let offset = 0;
|
|
234
|
+
for (const blank of text.matchAll(/\n[ \t]*\r?\n/g)) offset = blank.index + blank[0].length;
|
|
235
|
+
const block = text.slice(offset);
|
|
236
|
+
const lines = block.split('\n').map((line) => line.replace(/\r$/, ''));
|
|
237
|
+
if (lines.length === 0 || lines.length > 2 || !PIPE_ROW.test(lines[0])) return text;
|
|
238
|
+
if (lines.length === 2) {
|
|
239
|
+
const delimiter = lines[1];
|
|
240
|
+
if (!PARTIAL_DELIMITER_ROW.test(delimiter)) return text;
|
|
241
|
+
if (DELIMITER_ROW.test(delimiter) && tableCells(delimiter) === tableCells(lines[0])) return text;
|
|
242
|
+
}
|
|
243
|
+
return text.slice(0, offset);
|
|
244
|
+
}
|
|
245
|
+
|
|
216
246
|
export function healStreamingMarkdownTail(text, isPendingLocalPath) {
|
|
217
|
-
const
|
|
247
|
+
const source = String(text ?? '');
|
|
248
|
+
const fence = source.includes('`') || source.includes('~') ? openFence(source) : null;
|
|
249
|
+
if (fence) return trimPartialClosingFence(source, fence);
|
|
250
|
+
const value = source.includes('|') ? trimPendingTableHead(source) : source;
|
|
218
251
|
const hasSyntax = HEALABLE_MARKDOWN_SYNTAX.test(value);
|
|
219
252
|
if (!value || (!hasSyntax && !isPendingLocalPath)) return value;
|
|
220
|
-
const fence = openFence(value);
|
|
221
|
-
if (fence) return trimPartialClosingFence(value, fence);
|
|
222
253
|
const healed = hasSyntax
|
|
223
254
|
? closeEmphasis(healIncompleteLink(closeInlineCode(value, isPendingLocalPath), isPendingLocalPath))
|
|
224
255
|
: value;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { getModelMetadataSync } from '../../../../runtime/shared/llm/model-catalog.mjs';
|
|
5
|
+
import { providerCachedModelsSync } from '../../../../runtime/shared/llm/provider-catalog-cache.mjs';
|
|
4
6
|
|
|
5
7
|
export const CLAUDE_CURRENT_MODE = 'claude-current';
|
|
6
8
|
export const CLAUDE_CURRENT_CHOICE_ID = 'claude-current';
|
|
@@ -95,11 +97,21 @@ function snapshotEquivalent(a, b) {
|
|
|
95
97
|
return keys.every(k => (a[k] ?? null) === (b[k] ?? null));
|
|
96
98
|
}
|
|
97
99
|
|
|
100
|
+
// The newest roster model of a family, by the roster's own release stamps.
|
|
101
|
+
function newestRosterModel(family) {
|
|
102
|
+
const stamp = (row) => Date.parse(row.releaseDate) || (Number(row.created) > 0 ? Number(row.created) : 0);
|
|
103
|
+
const rows = providerCachedModelsSync('anthropic-oauth').filter((row) =>
|
|
104
|
+
String(row.id).toLowerCase().startsWith(`claude-${family}-`)
|
|
105
|
+
);
|
|
106
|
+
rows.sort((a, b) => stamp(b) - stamp(a));
|
|
107
|
+
return rows[0]?.id || null;
|
|
108
|
+
}
|
|
109
|
+
|
|
98
110
|
function familyDefaultModel(family) {
|
|
99
111
|
const f = String(family || '').toLowerCase();
|
|
100
112
|
if (!f) return null;
|
|
101
113
|
const envName = `ANTHROPIC_DEFAULT_${f.toUpperCase()}_MODEL`;
|
|
102
|
-
return cleanString(process.env[envName]) || DEFAULT_FAMILY_MODEL[f] || null;
|
|
114
|
+
return cleanString(process.env[envName]) || newestRosterModel(f) || DEFAULT_FAMILY_MODEL[f] || null;
|
|
103
115
|
}
|
|
104
116
|
|
|
105
117
|
export function stripClaudeContextSuffix(model) {
|
|
@@ -109,9 +121,7 @@ export function stripClaudeContextSuffix(model) {
|
|
|
109
121
|
function contextWindowFromRawModel(raw, resolved) {
|
|
110
122
|
const s = cleanString(raw).toLowerCase();
|
|
111
123
|
if (/\[1m\]/.test(s)) return 1000000;
|
|
112
|
-
|
|
113
|
-
if (/^claude-haiku-4-5/i.test(resolved || '')) return 200000;
|
|
114
|
-
return null;
|
|
124
|
+
return (resolved && getModelMetadataSync(resolved, 'anthropic-oauth')?.contextWindow) || null;
|
|
115
125
|
}
|
|
116
126
|
|
|
117
127
|
export function resolveClaudeModelAlias(model) {
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Pure, DB-free merge of session-fallback recall rows into the already-ranked
|
|
2
|
-
// global hybrid rows. Extracted into its own module so the starve-prevention +
|
|
3
|
-
// dedupe contract can be unit-tested without booting the memory worker (which
|
|
4
|
-
// has heavy top-level side effects: http server, pg, onnx embedding).
|
|
5
|
-
//
|
|
6
|
-
// Contract:
|
|
7
|
-
// - APPEND session rows, never prepend. Blind prepend lets session rows
|
|
8
|
-
// (limit+) starve the global first page and distorts sort/offset/limit.
|
|
9
|
-
// - Re-apply the SAME sort policy as the global path so global hybrid hits
|
|
10
|
-
// (carrying a real retrievalScore) keep their rank; session rows
|
|
11
|
-
// (retrievalScore 0 under importance, ts-ordered under date) only fill
|
|
12
|
-
// genuinely open slots.
|
|
13
|
-
// - Dedupe drops any session row whose id already appears as a global row OR
|
|
14
|
-
// as a global root's inlined chunk member (prevents member/leaf double
|
|
15
|
-
// output).
|
|
16
|
-
import { compareRecallByScore, compareRecallNewestFirst } from './recall-order.mjs';
|
|
17
|
-
|
|
18
|
-
export function mergeSessionRowsIntoGlobal(globalRows, sessionRows, { sort = 'importance' } = {}) {
|
|
19
|
-
const filtered = Array.isArray(globalRows) ? [...globalRows] : [];
|
|
20
|
-
if (!Array.isArray(sessionRows) || sessionRows.length === 0) return filtered;
|
|
21
|
-
const seen = new Set(filtered.map((r) => Number(r.id)));
|
|
22
|
-
for (const r of filtered) {
|
|
23
|
-
if (Array.isArray(r.members)) {
|
|
24
|
-
for (const m of r.members) seen.add(Number(m.id));
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const merged = sessionRows.filter((r) => !seen.has(Number(r.id)));
|
|
28
|
-
if (merged.length === 0) return filtered;
|
|
29
|
-
const out = [...filtered, ...merged];
|
|
30
|
-
out.sort(sort === 'date' ? compareRecallNewestFirst : compareRecallByScore);
|
|
31
|
-
return out;
|
|
32
|
-
}
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Long-range usage recovered from the durable session stores.
|
|
3
|
-
*
|
|
4
|
-
* The gateway event list is capped by row count and the daily rollup only
|
|
5
|
-
* carries days recorded after rolling up began, so both stores answer "what
|
|
6
|
-
* happened recently" and neither can answer "what did I ever spend on Grok".
|
|
7
|
-
* The session documents can: every session keeps its own lifetime token
|
|
8
|
-
* counters, its route, and its transcript timestamps, and they outlive both
|
|
9
|
-
* telemetry stores.
|
|
10
|
-
*
|
|
11
|
-
* So this module rebuilds per-day totals from those documents. The rebuild is
|
|
12
|
-
* a derivation, not a second recording: a day that the rollup or the raw
|
|
13
|
-
* events already cover is never taken from here, which is what keeps a turn
|
|
14
|
-
* from being counted twice.
|
|
15
|
-
*
|
|
16
|
-
* Two things are approximations, and both are marked `restored` so a surface
|
|
17
|
-
* can say so:
|
|
18
|
-
* - a session carries ONE set of token counters, so a session that changed
|
|
19
|
-
* model mid-way is attributed to the route it ended on;
|
|
20
|
-
* - those counters are not stamped per turn, so a session that spans days is
|
|
21
|
-
* split across them by how many messages each day holds.
|
|
22
|
-
*/
|
|
23
|
-
import { billableInputTokensForProvider, computeCostUsd } from './cost.mjs';
|
|
24
|
-
import { cleanId as clean, isConversationUsageSource, num, round6, usageRollupDayKey } from './usage-rollup.mjs';
|
|
25
|
-
|
|
26
|
-
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
27
|
-
|
|
28
|
-
/** Timestamp a transcript message was written at, when it carries one. */
|
|
29
|
-
function messageTimestamp(message) {
|
|
30
|
-
const direct = num(message?.createdAt);
|
|
31
|
-
if (direct > 0) return direct;
|
|
32
|
-
return num(message?.meta?.transcript?.at);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Spread `total` across `keys` in proportion to `weights`, keeping the sum
|
|
37
|
-
* exact: the rounding remainder lands on the heaviest day rather than
|
|
38
|
-
* disappearing from the totals.
|
|
39
|
-
*/
|
|
40
|
-
function distribute(total, keys, weights, weightSum) {
|
|
41
|
-
const out = new Map();
|
|
42
|
-
if (!(total > 0) || !keys.length) return out;
|
|
43
|
-
if (keys.length === 1 || !(weightSum > 0)) {
|
|
44
|
-
out.set(keys[0], total);
|
|
45
|
-
return out;
|
|
46
|
-
}
|
|
47
|
-
let assigned = 0;
|
|
48
|
-
let heaviest = keys[0];
|
|
49
|
-
let heaviestWeight = -1;
|
|
50
|
-
for (const key of keys) {
|
|
51
|
-
const weight = weights.get(key) || 0;
|
|
52
|
-
const share = Math.floor((total * weight) / weightSum);
|
|
53
|
-
out.set(key, share);
|
|
54
|
-
assigned += share;
|
|
55
|
-
if (weight > heaviestWeight) {
|
|
56
|
-
heaviest = key;
|
|
57
|
-
heaviestWeight = weight;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
if (assigned < total) out.set(heaviest, (out.get(heaviest) || 0) + (total - assigned));
|
|
61
|
-
return out;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* One session document → the per-day slices it contributes.
|
|
66
|
-
* Returns null for a session that never spent a token, which is most of the
|
|
67
|
-
* short-lived ids a daemon mints.
|
|
68
|
-
*/
|
|
69
|
-
export function summarizeSessionUsage(doc) {
|
|
70
|
-
const provider = clean(doc?.provider);
|
|
71
|
-
const model = clean(doc?.model);
|
|
72
|
-
if (!provider || !model) return null;
|
|
73
|
-
|
|
74
|
-
const cacheRead = num(doc?.totalCachedReadTokens);
|
|
75
|
-
const cacheWrite = num(doc?.totalCacheWriteTokens);
|
|
76
|
-
// `totalUncachedInputTokens` is already the billable part. Where a session
|
|
77
|
-
// predates that counter the raw input is unpacked the same way the rollup
|
|
78
|
-
// does it, so a provider that reports the cache inside `input` is not
|
|
79
|
-
// counted twice.
|
|
80
|
-
const input =
|
|
81
|
-
num(doc?.totalUncachedInputTokens) ||
|
|
82
|
-
billableInputTokensForProvider(provider, num(doc?.totalInputTokens), cacheRead, cacheWrite);
|
|
83
|
-
const output = num(doc?.totalOutputTokens);
|
|
84
|
-
if (input + output + cacheRead + cacheWrite <= 0) return null;
|
|
85
|
-
|
|
86
|
-
const messages = Array.isArray(doc?.messages) ? doc.messages : [];
|
|
87
|
-
const weights = new Map();
|
|
88
|
-
let weightSum = 0;
|
|
89
|
-
let firstTs = 0;
|
|
90
|
-
let lastTs = 0;
|
|
91
|
-
let userTurns = 0;
|
|
92
|
-
for (const message of messages) {
|
|
93
|
-
if (message?.role === 'user') userTurns += 1;
|
|
94
|
-
const ts = messageTimestamp(message);
|
|
95
|
-
if (ts <= 0) continue;
|
|
96
|
-
const key = usageRollupDayKey(ts);
|
|
97
|
-
weights.set(key, (weights.get(key) || 0) + 1);
|
|
98
|
-
weightSum += 1;
|
|
99
|
-
firstTs = firstTs > 0 ? Math.min(firstTs, ts) : ts;
|
|
100
|
-
lastTs = Math.max(lastTs, ts);
|
|
101
|
-
}
|
|
102
|
-
// A transcript compacted down to nothing still spent what it spent; the day
|
|
103
|
-
// it was last used is the only timestamp left to attribute it to.
|
|
104
|
-
if (!weights.size) {
|
|
105
|
-
const fallback = num(doc?.updatedAt) || num(doc?.lastUsedAt) || num(doc?.createdAt);
|
|
106
|
-
if (!fallback) return null;
|
|
107
|
-
const key = usageRollupDayKey(fallback);
|
|
108
|
-
weights.set(key, 1);
|
|
109
|
-
weightSum = 1;
|
|
110
|
-
firstTs = fallback;
|
|
111
|
-
lastTs = fallback;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const keys = [...weights.keys()].sort();
|
|
115
|
-
const turns = Math.max(1, userTurns);
|
|
116
|
-
const byInput = distribute(input, keys, weights, weightSum);
|
|
117
|
-
const byOutput = distribute(output, keys, weights, weightSum);
|
|
118
|
-
const byCacheRead = distribute(cacheRead, keys, weights, weightSum);
|
|
119
|
-
const byCacheWrite = distribute(cacheWrite, keys, weights, weightSum);
|
|
120
|
-
const byTurns = distribute(turns, keys, weights, weightSum);
|
|
121
|
-
|
|
122
|
-
const days = {};
|
|
123
|
-
for (const key of keys) {
|
|
124
|
-
const slice = {
|
|
125
|
-
turns: byTurns.get(key) || 0,
|
|
126
|
-
input: byInput.get(key) || 0,
|
|
127
|
-
output: byOutput.get(key) || 0,
|
|
128
|
-
cacheRead: byCacheRead.get(key) || 0,
|
|
129
|
-
cacheWrite: byCacheWrite.get(key) || 0,
|
|
130
|
-
costUsd: 0,
|
|
131
|
-
};
|
|
132
|
-
if (slice.turns + slice.input + slice.output + slice.cacheRead + slice.cacheWrite <= 0) continue;
|
|
133
|
-
let costUsd = 0;
|
|
134
|
-
try {
|
|
135
|
-
costUsd = num(
|
|
136
|
-
computeCostUsd({
|
|
137
|
-
provider,
|
|
138
|
-
model,
|
|
139
|
-
uncachedInputTokens: slice.input,
|
|
140
|
-
outputTokens: slice.output,
|
|
141
|
-
cacheReadTokens: slice.cacheRead,
|
|
142
|
-
cacheWriteTokens: slice.cacheWrite,
|
|
143
|
-
})
|
|
144
|
-
);
|
|
145
|
-
} catch {
|
|
146
|
-
// An unpriced model still reports its tokens.
|
|
147
|
-
}
|
|
148
|
-
slice.costUsd = round6(costUsd);
|
|
149
|
-
days[key] = slice;
|
|
150
|
-
}
|
|
151
|
-
if (!Object.keys(days).length) return null;
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
provider,
|
|
155
|
-
model,
|
|
156
|
-
sessionId: clean(doc?.id),
|
|
157
|
-
conversation: isConversationUsageSource(doc?.sourceType),
|
|
158
|
-
firstTs,
|
|
159
|
-
lastTs,
|
|
160
|
-
days,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function emptyRouteTotals() {
|
|
165
|
-
return { turns: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, costUsd: 0 };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function emptyTurnTotals() {
|
|
169
|
-
return {
|
|
170
|
-
...emptyRouteTotals(),
|
|
171
|
-
costBilled: 0,
|
|
172
|
-
// Nothing here was priced by a provider invoice: the catalog priced it.
|
|
173
|
-
costEstimated: 0,
|
|
174
|
-
costKnownTurns: 0,
|
|
175
|
-
durationMs: 0,
|
|
176
|
-
durationTurns: 0,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/** Rollup-shaped so the stats model folds a restored day with the same code. */
|
|
181
|
-
function emptyHistoryDay() {
|
|
182
|
-
return {
|
|
183
|
-
...emptyTurnTotals(),
|
|
184
|
-
firstTs: 0,
|
|
185
|
-
lastTs: 0,
|
|
186
|
-
conversation: emptyTurnTotals(),
|
|
187
|
-
conversationPartial: false,
|
|
188
|
-
sessionsPurged: true,
|
|
189
|
-
// Tells a reader these numbers were derived from transcripts rather than
|
|
190
|
-
// recorded turn by turn.
|
|
191
|
-
restored: true,
|
|
192
|
-
models: {},
|
|
193
|
-
sessions: {},
|
|
194
|
-
sessionTokens: [],
|
|
195
|
-
sessionsDropped: 0,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function addRouteTotals(target, slice) {
|
|
200
|
-
target.turns += slice.turns;
|
|
201
|
-
target.input += slice.input;
|
|
202
|
-
target.output += slice.output;
|
|
203
|
-
target.cacheRead += slice.cacheRead;
|
|
204
|
-
target.cacheWrite += slice.cacheWrite;
|
|
205
|
-
target.costUsd = round6(target.costUsd + slice.costUsd);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function addTurnTotals(target, slice) {
|
|
209
|
-
addRouteTotals(target, slice);
|
|
210
|
-
if (slice.costUsd > 0) {
|
|
211
|
-
target.costEstimated = round6(target.costEstimated + slice.costUsd);
|
|
212
|
-
target.costKnownTurns += slice.turns;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/** Fold every cached session summary into one day-keyed document. */
|
|
217
|
-
export function buildUsageHistoryDays(entries) {
|
|
218
|
-
const days = {};
|
|
219
|
-
for (const entry of entries) {
|
|
220
|
-
if (!entry?.provider || !entry?.model || !entry?.days) continue;
|
|
221
|
-
const routeKey = `${entry.provider}/${entry.model}`;
|
|
222
|
-
for (const [key, slice] of Object.entries(entry.days)) {
|
|
223
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(key)) continue;
|
|
224
|
-
const day = days[key] || emptyHistoryDay();
|
|
225
|
-
const normalized = {
|
|
226
|
-
turns: num(slice?.turns),
|
|
227
|
-
input: num(slice?.input),
|
|
228
|
-
output: num(slice?.output),
|
|
229
|
-
cacheRead: num(slice?.cacheRead),
|
|
230
|
-
cacheWrite: num(slice?.cacheWrite),
|
|
231
|
-
costUsd: num(slice?.costUsd),
|
|
232
|
-
};
|
|
233
|
-
addTurnTotals(day, normalized);
|
|
234
|
-
if (entry.conversation) addTurnTotals(day.conversation, normalized);
|
|
235
|
-
|
|
236
|
-
const bucket = day.models[routeKey] || {
|
|
237
|
-
provider: entry.provider,
|
|
238
|
-
model: entry.model,
|
|
239
|
-
kind: '',
|
|
240
|
-
...emptyRouteTotals(),
|
|
241
|
-
conversation: emptyRouteTotals(),
|
|
242
|
-
};
|
|
243
|
-
addRouteTotals(bucket, normalized);
|
|
244
|
-
if (entry.conversation) addRouteTotals(bucket.conversation, normalized);
|
|
245
|
-
day.models[routeKey] = bucket;
|
|
246
|
-
|
|
247
|
-
// Only conversation ids count as sessions, matching the rollup: a
|
|
248
|
-
// background runner mints a fresh id per cycle.
|
|
249
|
-
if (entry.conversation && entry.sessionId) {
|
|
250
|
-
const tokens = normalized.input + normalized.output + normalized.cacheRead + normalized.cacheWrite;
|
|
251
|
-
day.sessions[entry.sessionId] = (day.sessions[entry.sessionId] || 0) + tokens;
|
|
252
|
-
}
|
|
253
|
-
const dayStart = Date.parse(`${key}T00:00:00`);
|
|
254
|
-
if (Number.isFinite(dayStart)) {
|
|
255
|
-
const first = num(entry.firstTs);
|
|
256
|
-
const last = num(entry.lastTs);
|
|
257
|
-
const from = first > dayStart && first < dayStart + DAY_MS ? first : dayStart;
|
|
258
|
-
const to = last > dayStart && last < dayStart + DAY_MS ? last : dayStart + DAY_MS - 1;
|
|
259
|
-
day.firstTs = day.firstTs > 0 ? Math.min(day.firstTs, from) : from;
|
|
260
|
-
day.lastTs = Math.max(day.lastTs, to);
|
|
261
|
-
}
|
|
262
|
-
days[key] = day;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return days;
|
|
266
|
-
}
|