@vellumai/assistant 0.11.1 → 0.11.2-staging.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/Dockerfile +1 -3
- package/README.md +1 -1
- package/eslint.config.mjs +28 -8
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +48 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +25 -6
- package/openapi.yaml +292 -5
- package/package.json +1 -1
- package/src/__tests__/agent-loop-resume-interrupted.test.ts +223 -0
- package/src/__tests__/byok-default-profile-ensure.test.ts +43 -0
- package/src/__tests__/cli-logger-boundary-guard.test.ts +87 -0
- package/src/__tests__/compaction-events.test.ts +139 -2
- package/src/__tests__/config-loader-backfill.test.ts +35 -3
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +30 -0
- package/src/__tests__/conversation-agent-loop.test.ts +180 -7
- package/src/__tests__/conversation-error.test.ts +211 -4
- package/src/__tests__/conversation-options-turn-scoped-transport.test.ts +64 -0
- package/src/__tests__/conversation-queue.test.ts +126 -0
- package/src/__tests__/conversation-retry-route.test.ts +46 -7
- package/src/__tests__/conversation-slash.test.ts +4 -2
- package/src/__tests__/conversation-summarize-route.test.ts +7 -1
- package/src/__tests__/conversation-summarize-up-to.test.ts +71 -5
- package/src/__tests__/document-create-dedupe.test.ts +2 -1
- package/src/__tests__/document-find-replace.test.ts +2 -1
- package/src/__tests__/document-tool-security.test.ts +2 -1
- package/src/__tests__/document-update-default-surface.test.ts +2 -1
- package/src/__tests__/document-workspace-file.test.ts +467 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +290 -49
- package/src/__tests__/guardian-card-withdrawal.test.ts +91 -3
- package/src/__tests__/http-user-message-parity.test.ts +66 -0
- package/src/__tests__/list-messages-attachments.test.ts +87 -0
- package/src/__tests__/list-messages-provider-error.test.ts +143 -0
- package/src/__tests__/list-messages-system-card.test.ts +100 -0
- package/src/__tests__/llm-resolver.test.ts +19 -9
- package/src/__tests__/managed-profile-guard.test.ts +23 -0
- package/src/__tests__/notification-platform-adapter.test.ts +130 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +6 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +45 -0
- package/src/__tests__/plugin-api-model-profiles.test.ts +10 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -0
- package/src/__tests__/provider-error-scenarios.test.ts +140 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +95 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +66 -3
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +209 -0
- package/src/__tests__/skills.test.ts +27 -0
- package/src/__tests__/slack-channels-routes.test.ts +0 -2
- package/src/__tests__/slack-share-routes.test.ts +0 -3
- package/src/__tests__/slack-users-routes.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +11 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +58 -0
- package/src/__tests__/tool-result-spool.test.ts +5 -4
- package/src/__tests__/turn-boundary-resolution.test.ts +53 -0
- package/src/__tests__/turn-events-store.test.ts +26 -0
- package/src/__tests__/ui-visual-surface.test.ts +695 -0
- package/src/__tests__/unified-turn-context-visible-app.test.ts +99 -0
- package/src/__tests__/visible-app-context.test.ts +189 -0
- package/src/__tests__/workspace-git-service.test.ts +173 -33
- package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +157 -0
- package/src/__tests__/workspace-migration-138-backfill-home-feed-titles.test.ts +373 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +137 -0
- package/src/agent/loop.ts +36 -7
- package/src/api/events/context-window-usage.ts +31 -0
- package/src/api/events/notification-intent.ts +8 -0
- package/src/api/events/ui-surface-pending.ts +35 -0
- package/src/api/index.ts +14 -0
- package/src/api/responses/conversation-message.ts +25 -4
- package/src/api/surfaces.ts +90 -1
- package/src/approvals/guardian-card-withdrawal.ts +66 -31
- package/src/approvals/guardian-decision-primitive.ts +4 -0
- package/src/calls/__tests__/call-setup-router.test.ts +156 -26
- package/src/calls/__tests__/voice-session-bridge.test.ts +201 -12
- package/src/calls/call-setup-router.ts +80 -36
- package/src/calls/voice-session-bridge.ts +173 -26
- package/src/cli/commands/inference.help.ts +3 -3
- package/src/cli/commands/notifications.help.ts +3 -2
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +42 -128
- package/src/cli/commands/platform/__tests__/credits.test.ts +9 -78
- package/src/cli/commands/platform/__tests__/helpers.ts +90 -0
- package/src/cli/commands/platform/__tests__/invoices.test.ts +238 -0
- package/src/cli/commands/platform/__tests__/plans.test.ts +9 -88
- package/src/cli/commands/platform/__tests__/status.test.ts +12 -87
- package/src/cli/commands/platform/__tests__/subscription.test.ts +9 -86
- package/src/cli/commands/platform/index.help.ts +92 -0
- package/src/cli/commands/platform/index.ts +7 -0
- package/src/cli/commands/platform/invoices.ts +132 -0
- package/src/cli/commands/usage.help.ts +1 -1
- package/src/cli/lib/list-installed-plugins.ts +2 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +7 -10
- package/src/config/__tests__/deployment-context-defaults.test.ts +27 -5
- package/src/config/assistant-feature-flags.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -2
- package/src/config/bundled-skills/subagent/SKILL.md +3 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +3 -3
- package/src/config/bundled-skills/visualize/SKILL.md +163 -0
- package/src/config/call-site-defaults.ts +3 -2
- package/src/config/default-profile-catalog.ts +75 -70
- package/src/config/default-profile-names.ts +13 -28
- package/src/config/env-registry.ts +1 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +21 -5
- package/src/config/loader.ts +18 -11
- package/src/config/schemas/llm.ts +1 -9
- package/src/config/schemas/memory-retrospective.ts +9 -0
- package/src/config/schemas/monitoring.ts +28 -2
- package/src/config/schemas/workspace-git.ts +15 -0
- package/src/config/seed-inference-profiles.ts +19 -5
- package/src/context/post-turn-tool-result-truncation.ts +2 -2
- package/src/conversations/__tests__/message-consolidation.test.ts +54 -0
- package/src/conversations/message-consolidation.ts +17 -15
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +182 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +181 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +90 -7
- package/src/daemon/conversation-agent-loop.ts +107 -22
- package/src/daemon/conversation-error.ts +169 -48
- package/src/daemon/conversation-messaging.ts +87 -4
- package/src/daemon/conversation-process.ts +57 -45
- package/src/daemon/conversation-runtime-assembly.ts +57 -0
- package/src/daemon/conversation-store.ts +36 -1
- package/src/daemon/conversation-surfaces.ts +68 -6
- package/src/daemon/conversation-turn-finalize.ts +76 -18
- package/src/daemon/conversation.ts +122 -27
- package/src/daemon/lifecycle.ts +9 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/surfaces.ts +3 -0
- package/src/documents/document-store.ts +247 -10
- package/src/home/__tests__/feed-types.test.ts +43 -8
- package/src/home/__tests__/feed-writer.test.ts +59 -0
- package/src/home/feed-types.ts +34 -7
- package/src/home/feed-writer.ts +15 -6
- package/src/live-voice/__tests__/activity-label.test.ts +95 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +86 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +310 -25
- package/src/live-voice/__tests__/live-voice-events.test.ts +4 -4
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +8 -4
- package/src/live-voice/__tests__/live-voice-vad.test.ts +9 -1
- package/src/live-voice/activity-label.ts +169 -0
- package/src/live-voice/live-activity-reporter.ts +35 -6
- package/src/live-voice/live-voice-session.ts +282 -41
- package/src/live-voice/protocol.ts +35 -0
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +84 -2
- package/src/messaging/providers/slack/adapter.ts +86 -19
- package/src/messaging/providers/slack/api.test.ts +85 -1
- package/src/messaging/providers/slack/api.ts +121 -288
- package/src/messaging/providers/slack/client.ts +20 -251
- package/src/messaging/providers/slack/send.test.ts +4 -9
- package/src/messaging/providers/slack/send.ts +1 -1
- package/src/messaging/providers/slack/types.ts +5 -0
- package/src/messaging/providers/slack/web-api-transport.test.ts +181 -0
- package/src/messaging/providers/slack/web-api-transport.ts +367 -0
- package/src/messaging/providers/slack/withdraw.ts +6 -14
- package/src/messaging/providers/telegram-bot/send.test.ts +31 -1
- package/src/messaging/providers/telegram-bot/send.ts +23 -2
- package/src/messaging/providers/telegram-bot/withdraw.test.ts +152 -0
- package/src/messaging/providers/telegram-bot/withdraw.ts +166 -0
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +18 -4
- package/src/monitoring/__tests__/file-descriptors.test.ts +144 -0
- package/src/monitoring/file-descriptors.ts +262 -0
- package/src/monitoring/process-memory.ts +4 -11
- package/src/monitoring/resource-sampler.ts +5 -0
- package/src/monitoring/worker.ts +12 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +740 -0
- package/src/notifications/__tests__/broadcaster.test.ts +347 -7
- package/src/notifications/__tests__/copy-composer.test.ts +53 -3
- package/src/notifications/__tests__/decision-engine.test.ts +349 -29
- package/src/notifications/__tests__/deterministic-checks.test.ts +21 -0
- package/src/notifications/__tests__/edit-notification.test.ts +330 -0
- package/src/notifications/__tests__/guardian-delivery-recorder.test.ts +71 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +170 -12
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/adapters/platform.ts +90 -14
- package/src/notifications/adapters/telegram.ts +6 -4
- package/src/notifications/assistant-reply-producer.ts +219 -0
- package/src/notifications/broadcaster.ts +523 -317
- package/src/notifications/copy-composer.ts +27 -6
- package/src/notifications/decision-engine.ts +154 -77
- package/src/notifications/deterministic-checks.ts +6 -7
- package/src/notifications/edit-notification.ts +8 -4
- package/src/notifications/emit-signal.ts +49 -16
- package/src/notifications/guardian-delivery-recorder.ts +8 -2
- package/src/notifications/home-feed-side-effect.ts +43 -6
- package/src/notifications/notification-utils.ts +39 -4
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +17 -0
- package/src/persistence/bookmark-crud.ts +18 -9
- package/src/persistence/conversation-attention-store.ts +26 -0
- package/src/persistence/conversation-crud.ts +79 -32
- package/src/persistence/conversation-queries.ts +30 -15
- package/src/persistence/conversation-title-service.ts +5 -170
- package/src/persistence/conversation-types.ts +192 -1
- package/src/persistence/db-init.ts +14 -1
- package/src/persistence/db-maintenance.ts +5 -4
- package/src/persistence/embeddings/__tests__/plugin-index-qdrant-init.test.ts +219 -0
- package/src/persistence/embeddings/__tests__/plugin-index.test.ts +22 -0
- package/src/persistence/embeddings/__tests__/worker-script-version.test.ts +76 -0
- package/src/persistence/embeddings/embedding-local.ts +2 -1
- package/src/persistence/embeddings/embedding-runtime-manager.ts +29 -5
- package/src/persistence/embeddings/plugin-index.ts +84 -12
- package/src/persistence/migrations/360-add-document-workspace-path.test.ts +110 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +39 -0
- package/src/persistence/planner-statistics.ts +14 -0
- package/src/persistence/schema/documents.ts +26 -11
- package/src/persistence/steps.ts +2 -0
- package/src/platform/client.test.ts +172 -2
- package/src/platform/client.ts +178 -55
- package/src/plugin-api/conversation-turn.ts +13 -0
- package/src/plugin-api/model-profiles.test.ts +6 -2
- package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +34 -0
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +22 -0
- package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +11 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +199 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +98 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +105 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +24 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +524 -0
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +9 -4
- package/src/plugins/defaults/memory/host-utils.ts +5 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +105 -1
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +64 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +36 -1
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +12 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +1 -0
- package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +195 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +1 -1
- package/src/plugins/defaults/memory/substrate/skill-store.ts +167 -29
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +131 -0
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1 -0
- package/src/plugins/defaults/memory/v2/activation-log-store.ts +4 -0
- package/src/plugins/defaults/memory/v2/injection.ts +48 -3
- package/src/plugins/defaults/memory/v2/rerank-local.ts +6 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -1
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +1 -1
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +26 -0
- package/src/plugins/types.ts +17 -0
- package/src/prompts/templates/system-sections.ts +2 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +43 -2
- package/src/providers/__tests__/vellum-mismatch-routing.test.ts +8 -0
- package/src/providers/call-site-routing.ts +77 -14
- package/src/providers/connection-resolution.ts +42 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +127 -1
- package/src/providers/inference/adapter-factory.ts +70 -12
- package/src/providers/model-catalog.ts +0 -11
- package/src/providers/model-intents.ts +11 -0
- package/src/providers/registry.ts +8 -0
- package/src/providers/retry.ts +85 -17
- package/src/providers/types.ts +8 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/agent-wake.ts +132 -9
- package/src/runtime/channel-approval-types.ts +25 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +2 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +11 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +121 -9
- package/src/runtime/routes/__tests__/platform-invoice-routes.test.ts +392 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/workspace-commit-routes.test.ts +63 -0
- package/src/runtime/routes/consolidation-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +18 -6
- package/src/runtime/routes/conversation-query-routes.ts +14 -23
- package/src/runtime/routes/conversation-routes.ts +113 -8
- package/src/runtime/routes/credential-routes.ts +1 -5
- package/src/runtime/routes/documents-routes.ts +207 -12
- package/src/runtime/routes/identity-routes.ts +3 -93
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +31 -1
- package/src/runtime/routes/inbound-stages/admission-policy.ts +18 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +52 -3
- package/src/runtime/routes/notification-routes.ts +4 -1
- package/src/runtime/routes/platform-routes.ts +238 -3
- package/src/runtime/routes/playground/guard.ts +1 -2
- package/src/runtime/routes/slack-channel-routes.ts +2 -4
- package/src/runtime/routes/workspace-commit-routes.ts +49 -2
- package/src/runtime/routes/workspace-routes.ts +11 -12
- package/src/runtime/routes/workspace-utils.ts +49 -2
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/subagent/__tests__/consult-context-gating.test.ts +98 -0
- package/src/subagent/__tests__/consult-context-skills.test.ts +82 -0
- package/src/subagent/__tests__/consult-context.test.ts +84 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +36 -0
- package/src/subagent/consult-context.ts +410 -0
- package/src/subagent/consult-prompt.ts +38 -5
- package/src/subagent/manager.ts +9 -4
- package/src/subagent/types.ts +8 -0
- package/src/telemetry/telemetry-event-sources.ts +7 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +1 -0
- package/src/telemetry/turn-events-store.ts +30 -1
- package/src/telemetry/types.ts +24 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/tools/browser/pinned-tabs.ts +3 -1
- package/src/tools/subagent/spawn.ts +23 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/ui-surface/definitions.ts +39 -1
- package/src/tools/ui-surface/surface-shape-docs.ts +38 -4
- package/src/tools/ui-surface/visual-validation.ts +787 -0
- package/src/tools/workflows/run-workflow.test.ts +1 -0
- package/src/util/__tests__/short-title.test.ts +229 -0
- package/src/util/__tests__/worker-compute.test.ts +65 -0
- package/src/util/cgroup-cpu.ts +93 -0
- package/src/util/errors.ts +27 -0
- package/src/util/process-tree.ts +19 -0
- package/src/util/short-title.ts +189 -0
- package/src/util/worker-compute.ts +83 -0
- package/src/workspace/byok-default-profile-ensure.ts +25 -15
- package/src/workspace/git-service.ts +79 -30
- package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +131 -0
- package/src/workspace/migrations/138-backfill-home-feed-titles.ts +179 -0
- package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +92 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/plugins/defaults/memory/substrate/constants.ts +0 -8
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONNX Runtime thread tuning for the local ML worker subprocesses (embed,
|
|
3
|
+
* rerank).
|
|
4
|
+
*
|
|
5
|
+
* ONNX Runtime sizes its intra-op thread pool from the machine's physical core
|
|
6
|
+
* count when nothing says otherwise. An unhinted worker therefore takes every
|
|
7
|
+
* core for the duration of an inference batch. On a developer laptop that pins
|
|
8
|
+
* the machine and spins the fans; in a container it oversubscribes a CPU quota
|
|
9
|
+
* the scheduler then throttles.
|
|
10
|
+
*
|
|
11
|
+
* The work is background indexing the user neither initiated nor can see, so
|
|
12
|
+
* it should not preempt foreground work. Capping the pool trades batch latency
|
|
13
|
+
* for leaving the rest of the system responsive, the same trade as spawning
|
|
14
|
+
* these workers with `--smol`.
|
|
15
|
+
*
|
|
16
|
+
* Unlike the memory hint in worker-memory.ts, this is a hard cap: ONNX will
|
|
17
|
+
* not exceed the configured thread count.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { getContainerCpuCores } from "./cgroup-cpu.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Environment variable carrying the computed cap to the worker script. The
|
|
24
|
+
* worker is a standalone bun process that reads this and passes it to ONNX as
|
|
25
|
+
* `session_options.intraOpNumThreads`.
|
|
26
|
+
*/
|
|
27
|
+
export const ONNX_INTRA_OP_THREADS_ENV = "VELLUM_ONNX_INTRA_OP_THREADS";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Fraction of available cores one ML worker's intra-op pool may use. The
|
|
31
|
+
* machine is shared with the daemon, the gateway, tool subprocesses, and
|
|
32
|
+
* (because embed and rerank are separate processes) potentially a second ML
|
|
33
|
+
* worker, so one of them gets a quarter.
|
|
34
|
+
*/
|
|
35
|
+
const WORKER_CPU_FRACTION = 0.25;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Lower clamp. ONNX treats a non-positive thread count as "pick for me", which
|
|
39
|
+
* is the unbounded default this module exists to prevent, so the floor is 1.
|
|
40
|
+
*/
|
|
41
|
+
export const WORKER_MIN_INTRA_OP_THREADS = 1;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Upper clamp. Intra-op scaling for models this size flattens well before this
|
|
45
|
+
* point; past it, extra threads add synchronization overhead and heat without
|
|
46
|
+
* shortening the batch.
|
|
47
|
+
*/
|
|
48
|
+
export const WORKER_MAX_INTRA_OP_THREADS = 4;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Intra-op thread cap for an ML worker, derived from the container CPU limit
|
|
52
|
+
* (the visible core count when no container limit applies, e.g. local dev),
|
|
53
|
+
* clamped to [{@link WORKER_MIN_INTRA_OP_THREADS}, {@link WORKER_MAX_INTRA_OP_THREADS}].
|
|
54
|
+
*
|
|
55
|
+
* A zero or negative core count means detection failed entirely; fall back to
|
|
56
|
+
* the floor rather than handing ONNX a value it would read as "unbounded".
|
|
57
|
+
*/
|
|
58
|
+
export function computeWorkerIntraOpThreads(cores: number): number {
|
|
59
|
+
if (!Number.isFinite(cores) || cores <= 0) {
|
|
60
|
+
return WORKER_MIN_INTRA_OP_THREADS;
|
|
61
|
+
}
|
|
62
|
+
const target = Math.floor(cores * WORKER_CPU_FRACTION);
|
|
63
|
+
return Math.min(
|
|
64
|
+
WORKER_MAX_INTRA_OP_THREADS,
|
|
65
|
+
Math.max(WORKER_MIN_INTRA_OP_THREADS, target),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Environment additions for spawning an ONNX worker: the intra-op thread cap.
|
|
71
|
+
* An operator-provided value in the parent environment wins over the computed
|
|
72
|
+
* one, matching how `workerMemoryEnv` treats `BUN_JSC_forceRAMSize`.
|
|
73
|
+
*
|
|
74
|
+
* Returns only the compute keys, so spread this over `workerMemoryEnv()`,
|
|
75
|
+
* which carries the full parent environment.
|
|
76
|
+
*/
|
|
77
|
+
export function workerComputeEnv(): Record<string, string> {
|
|
78
|
+
return {
|
|
79
|
+
[ONNX_INTRA_OP_THREADS_ENV]:
|
|
80
|
+
process.env[ONNX_INTRA_OP_THREADS_ENV] ??
|
|
81
|
+
String(computeWorkerIntraOpThreads(getContainerCpuCores())),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -7,10 +7,7 @@ import {
|
|
|
7
7
|
resolveDefaultProfileForProvider,
|
|
8
8
|
USER_PROFILE_TEMPLATES,
|
|
9
9
|
} from "../config/default-profile-catalog.js";
|
|
10
|
-
import {
|
|
11
|
-
DEFAULT_PROFILE_KEYS,
|
|
12
|
-
type DefaultProfileKey,
|
|
13
|
-
} from "../config/default-profile-names.js";
|
|
10
|
+
import type { DefaultProfileKey } from "../config/default-profile-names.js";
|
|
14
11
|
import { getIsPlatform } from "../config/env-registry.js";
|
|
15
12
|
import { invalidateConfigCache } from "../config/loader.js";
|
|
16
13
|
import {
|
|
@@ -65,6 +62,19 @@ const log = getLogger("byok-default-profile-ensure");
|
|
|
65
62
|
// Idempotent and write-avoidant: the file is rewritten only when at least one
|
|
66
63
|
// stub or copy was removed.
|
|
67
64
|
|
|
65
|
+
/**
|
|
66
|
+
* The default keys BYOK hatching writes to disk. `latency-optimized` is absent
|
|
67
|
+
* by construction: no install carries a hatch stub or a
|
|
68
|
+
* `custom-latency-optimized` copy for it, and listing it here would make
|
|
69
|
+
* `uniformCopyProvider` demand a copy that cannot exist and convert nothing.
|
|
70
|
+
*/
|
|
71
|
+
const HATCH_ERA_PROFILE_KEYS = [
|
|
72
|
+
"balanced",
|
|
73
|
+
"quality-optimized",
|
|
74
|
+
"cost-optimized",
|
|
75
|
+
] as const satisfies readonly DefaultProfileKey[];
|
|
76
|
+
type HatchEraProfileKey = (typeof HATCH_ERA_PROFILE_KEYS)[number];
|
|
77
|
+
|
|
68
78
|
/**
|
|
69
79
|
* The exact stub shapes BYOK hatching left on each default key: thin (only
|
|
70
80
|
* the workspace-owned overlay fields), `source: "managed"`, the frozen
|
|
@@ -82,7 +92,7 @@ const log = getLogger("byok-default-profile-ensure");
|
|
|
82
92
|
* alone.
|
|
83
93
|
*/
|
|
84
94
|
const STUB_ONLY_KEYS = new Set(["source", "status", "label", "thinking"]);
|
|
85
|
-
const HATCH_STUB_LABELS: Record<
|
|
95
|
+
const HATCH_STUB_LABELS: Record<HatchEraProfileKey, string> = {
|
|
86
96
|
balanced: "Balanced (Managed)",
|
|
87
97
|
"quality-optimized": "Quality (Managed)",
|
|
88
98
|
"cost-optimized": "Speed (Managed)",
|
|
@@ -100,7 +110,7 @@ const HATCH_STUB_LABELS: Record<DefaultProfileKey, string> = {
|
|
|
100
110
|
const REPAIR_WRITTEN_THINKING = { enabled: true, streamThinking: true };
|
|
101
111
|
|
|
102
112
|
function isHatchStub(
|
|
103
|
-
key:
|
|
113
|
+
key: HatchEraProfileKey,
|
|
104
114
|
entry: Record<string, unknown>,
|
|
105
115
|
): boolean {
|
|
106
116
|
return (
|
|
@@ -142,7 +152,7 @@ const IGNORED_COMPARISON_KEYS = new Set(["label", "status", "model"]);
|
|
|
142
152
|
* field still matches the template.
|
|
143
153
|
*/
|
|
144
154
|
const HISTORICAL_INTENT_MODELS: Record<
|
|
145
|
-
|
|
155
|
+
HatchEraProfileKey,
|
|
146
156
|
Partial<Record<string, readonly string[]>>
|
|
147
157
|
> = {
|
|
148
158
|
balanced: {
|
|
@@ -231,7 +241,7 @@ export function ensureByokDefaultProfiles(workspaceDir: string): void {
|
|
|
231
241
|
|
|
232
242
|
// Deleting a hatch stub makes the default key resolve active from the
|
|
233
243
|
// default provider's catalog column (and drops the stub's suffixed label).
|
|
234
|
-
for (const key of
|
|
244
|
+
for (const key of HATCH_ERA_PROFILE_KEYS) {
|
|
235
245
|
const entry = readObject(profiles[key]);
|
|
236
246
|
if (entry === null || !isHatchStub(key, entry)) {
|
|
237
247
|
continue;
|
|
@@ -260,8 +270,8 @@ export function ensureByokDefaultProfiles(workspaceDir: string): void {
|
|
|
260
270
|
: null;
|
|
261
271
|
|
|
262
272
|
const retired = new Map<string, string>();
|
|
263
|
-
const carriedDisables = new Set<
|
|
264
|
-
for (const key of
|
|
273
|
+
const carriedDisables = new Set<HatchEraProfileKey>();
|
|
274
|
+
for (const key of HATCH_ERA_PROFILE_KEYS) {
|
|
265
275
|
const name = `custom-${key}`;
|
|
266
276
|
const entry = readObject(profiles[name]);
|
|
267
277
|
if (
|
|
@@ -318,7 +328,7 @@ export function ensureByokDefaultProfiles(workspaceDir: string): void {
|
|
|
318
328
|
|
|
319
329
|
function isKnownUneditedBody(
|
|
320
330
|
entry: Record<string, unknown>,
|
|
321
|
-
key:
|
|
331
|
+
key: HatchEraProfileKey,
|
|
322
332
|
convertibleProvider: LLMProvider | null,
|
|
323
333
|
completionBase: LLMConfigBase | undefined,
|
|
324
334
|
): boolean {
|
|
@@ -374,7 +384,7 @@ function isKnownUneditedBody(
|
|
|
374
384
|
*/
|
|
375
385
|
function uniformCopyProvider(profiles: Record<string, unknown>): string | null {
|
|
376
386
|
let provider: string | null = null;
|
|
377
|
-
for (const key of
|
|
387
|
+
for (const key of HATCH_ERA_PROFILE_KEYS) {
|
|
378
388
|
const entry = readObject(profiles[`custom-${key}`]);
|
|
379
389
|
if (entry === null) {
|
|
380
390
|
return null;
|
|
@@ -415,7 +425,7 @@ function uniformCopyProvider(profiles: Record<string, unknown>): string | null {
|
|
|
415
425
|
*/
|
|
416
426
|
function hatchBodyVariants(
|
|
417
427
|
known: Record<string, unknown>,
|
|
418
|
-
key:
|
|
428
|
+
key: HatchEraProfileKey,
|
|
419
429
|
copyProvider: string,
|
|
420
430
|
): Record<string, unknown>[] {
|
|
421
431
|
let variants = [known];
|
|
@@ -460,7 +470,7 @@ function withCompletionBaked(
|
|
|
460
470
|
*/
|
|
461
471
|
function userOverlayState(
|
|
462
472
|
entry: Record<string, unknown>,
|
|
463
|
-
key:
|
|
473
|
+
key: HatchEraProfileKey,
|
|
464
474
|
): Record<string, unknown> | null {
|
|
465
475
|
const overlay: Record<string, unknown> = {};
|
|
466
476
|
const templateLabel = USER_PROFILE_TEMPLATES[`custom-${key}`]?.label;
|
|
@@ -566,7 +576,7 @@ function repairProfileSelections(
|
|
|
566
576
|
llm: Record<string, unknown>,
|
|
567
577
|
profiles: Record<string, unknown>,
|
|
568
578
|
defaultProvider: DefaultProviderConfig,
|
|
569
|
-
carriedDisables: ReadonlySet<
|
|
579
|
+
carriedDisables: ReadonlySet<HatchEraProfileKey>,
|
|
570
580
|
): void {
|
|
571
581
|
const effectiveEntry = (name: string): ProfileEntry | undefined =>
|
|
572
582
|
resolveDefaultProfileForProvider(
|
|
@@ -915,6 +915,15 @@ export class WorkspaceGitService {
|
|
|
915
915
|
);
|
|
916
916
|
}
|
|
917
917
|
|
|
918
|
+
/**
|
|
919
|
+
* Whether background history compaction is enabled for this workspace.
|
|
920
|
+
* Gates only the scheduler — {@link compactHistoryNow} stays callable so
|
|
921
|
+
* operators can compact manually while automatic runs are off.
|
|
922
|
+
*/
|
|
923
|
+
private isHistoryCompactionEnabled(): boolean {
|
|
924
|
+
return getConfig().workspaceGit?.historyCompaction?.enabled ?? true;
|
|
925
|
+
}
|
|
926
|
+
|
|
918
927
|
/**
|
|
919
928
|
* Working-tree size check for a repo-relative path. Uses lstat so a
|
|
920
929
|
* symlink is measured by the link itself, not its target. Missing or
|
|
@@ -1003,10 +1012,21 @@ export class WorkspaceGitService {
|
|
|
1003
1012
|
* history is still within retention, the attempt reschedules itself for
|
|
1004
1013
|
* when the oldest commit ages past the cutoff. Best-effort like the
|
|
1005
1014
|
* untrack sweeps: failures are logged and never affect commits.
|
|
1015
|
+
*
|
|
1016
|
+
* Gated by workspaceGit.historyCompaction.enabled, checked both here and
|
|
1017
|
+
* when the timer fires (config hot-reloads, so a pending timer must honor
|
|
1018
|
+
* a flip to disabled).
|
|
1006
1019
|
*/
|
|
1007
1020
|
private scheduleHistoryCompaction(
|
|
1008
1021
|
delayMs = HISTORY_COMPACTION_INITIAL_DELAY_MS,
|
|
1009
1022
|
): void {
|
|
1023
|
+
if (!this.isHistoryCompactionEnabled()) {
|
|
1024
|
+
log.debug(
|
|
1025
|
+
{ workspaceDir: this.workspaceDir },
|
|
1026
|
+
"Background history compaction disabled by config; not scheduling",
|
|
1027
|
+
);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1010
1030
|
const dueAtMs = Date.now() + delayMs;
|
|
1011
1031
|
if (this.historyCompactionTimer) {
|
|
1012
1032
|
if (dueAtMs >= this.historyCompactionDueAtMs) {
|
|
@@ -1020,6 +1040,14 @@ export class WorkspaceGitService {
|
|
|
1020
1040
|
}
|
|
1021
1041
|
const timer = setTimeout(() => {
|
|
1022
1042
|
void (async () => {
|
|
1043
|
+
if (!this.isHistoryCompactionEnabled()) {
|
|
1044
|
+
log.debug(
|
|
1045
|
+
{ workspaceDir: this.workspaceDir },
|
|
1046
|
+
"Background history compaction disabled by config; skipping scheduled run",
|
|
1047
|
+
);
|
|
1048
|
+
this.historyCompactionTimer = null;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1023
1051
|
let retryAfterMs: number | undefined;
|
|
1024
1052
|
try {
|
|
1025
1053
|
const result = await this.compactHistoryNow();
|
|
@@ -1044,14 +1072,19 @@ export class WorkspaceGitService {
|
|
|
1044
1072
|
|
|
1045
1073
|
/**
|
|
1046
1074
|
* Rewrite workspace history so blobs over workspaceGit.maxFileSizeBytes
|
|
1047
|
-
* stop occupying .git. Commits older than
|
|
1075
|
+
* stop occupying .git. Commits older than the retention window
|
|
1076
|
+
* (HISTORY_RETENTION_DAYS unless `retentionDays` overrides it) are
|
|
1048
1077
|
* squashed into a single base commit whose tree is scrubbed of oversized
|
|
1049
1078
|
* entries; younger commits are replayed verbatim (trees, messages,
|
|
1050
1079
|
* authors, and dates preserved); reflogs are then expired and unreachable
|
|
1051
|
-
* objects pruned.
|
|
1052
|
-
* blob that is actionable — unreachable, or reachable at a
|
|
1053
|
-
* path (see SIZE_GUARD_EXEMPT_PATTERNS) — so the steady state
|
|
1054
|
-
* detection scan and exempt canonical state never triggers
|
|
1080
|
+
* objects pruned. By default runs only when the object store contains an
|
|
1081
|
+
* oversized blob that is actionable — unreachable, or reachable at a
|
|
1082
|
+
* non-exempt path (see SIZE_GUARD_EXEMPT_PATTERNS) — so the steady state
|
|
1083
|
+
* is a cheap detection scan and exempt canonical state never triggers
|
|
1084
|
+
* rewrites. With `force`, the squash runs unconditionally whenever any
|
|
1085
|
+
* commit is older than the cutoff — the manual path for reclaiming bulk
|
|
1086
|
+
* history (including old versions of exempt canonical state referenced
|
|
1087
|
+
* only by squashed commits).
|
|
1055
1088
|
*
|
|
1056
1089
|
* Oversized blobs still referenced by replayed recent commits survive
|
|
1057
1090
|
* until those commits age past retention — the result carries
|
|
@@ -1061,7 +1094,12 @@ export class WorkspaceGitService {
|
|
|
1061
1094
|
* Git notes attached to rewritten commits are orphaned; enrichment only
|
|
1062
1095
|
* targets commits created after the rewrite, so this is cosmetic.
|
|
1063
1096
|
*/
|
|
1064
|
-
async compactHistoryNow(
|
|
1097
|
+
async compactHistoryNow(options?: {
|
|
1098
|
+
/** Squash aged history even when no oversized blob is actionable. */
|
|
1099
|
+
force?: boolean;
|
|
1100
|
+
/** Retention window override in days for this run. */
|
|
1101
|
+
retentionDays?: number;
|
|
1102
|
+
}): Promise<{
|
|
1065
1103
|
rewrote: boolean;
|
|
1066
1104
|
squashedCommits: number;
|
|
1067
1105
|
keptCommits: number;
|
|
@@ -1069,7 +1107,7 @@ export class WorkspaceGitService {
|
|
|
1069
1107
|
retryAfterMs?: number;
|
|
1070
1108
|
}> {
|
|
1071
1109
|
await this.ensureInitialized();
|
|
1072
|
-
return this.mutex.withLock(() => this.compactHistoryLocked());
|
|
1110
|
+
return this.mutex.withLock(() => this.compactHistoryLocked(options));
|
|
1073
1111
|
}
|
|
1074
1112
|
|
|
1075
1113
|
/**
|
|
@@ -1180,7 +1218,10 @@ export class WorkspaceGitService {
|
|
|
1180
1218
|
return remaining.size > 0 ? "prunable" : "none";
|
|
1181
1219
|
}
|
|
1182
1220
|
|
|
1183
|
-
private async compactHistoryLocked(
|
|
1221
|
+
private async compactHistoryLocked(options?: {
|
|
1222
|
+
force?: boolean;
|
|
1223
|
+
retentionDays?: number;
|
|
1224
|
+
}): Promise<{
|
|
1184
1225
|
rewrote: boolean;
|
|
1185
1226
|
squashedCommits: number;
|
|
1186
1227
|
keptCommits: number;
|
|
@@ -1188,11 +1229,13 @@ export class WorkspaceGitService {
|
|
|
1188
1229
|
}> {
|
|
1189
1230
|
const noop = { rewrote: false, squashedCommits: 0, keptCommits: 0 };
|
|
1190
1231
|
const limit = this.maxFileSizeBytes();
|
|
1232
|
+
const force = options?.force === true;
|
|
1233
|
+
const retentionDays = options?.retentionDays ?? HISTORY_RETENTION_DAYS;
|
|
1191
1234
|
|
|
1192
1235
|
// Any oversized blobs at all? Bounds the cost of every boot where there
|
|
1193
|
-
// is nothing to do.
|
|
1236
|
+
// is nothing to do. Forced runs squash regardless.
|
|
1194
1237
|
const oversizedOids = await this.collectOversizedBlobOidsLocked(limit);
|
|
1195
|
-
if (oversizedOids.size === 0) {
|
|
1238
|
+
if (oversizedOids.size === 0 && !force) {
|
|
1196
1239
|
return noop;
|
|
1197
1240
|
}
|
|
1198
1241
|
|
|
@@ -1236,31 +1279,39 @@ export class WorkspaceGitService {
|
|
|
1236
1279
|
return noop;
|
|
1237
1280
|
}
|
|
1238
1281
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1282
|
+
// Forced runs skip classification: they squash whenever aged history
|
|
1283
|
+
// exists, so the reachable/exempt distinction does not short-circuit.
|
|
1284
|
+
if (!force) {
|
|
1285
|
+
const verdict = await this.classifyOversizedBlobsLocked(oversizedOids);
|
|
1286
|
+
if (verdict === "none") {
|
|
1287
|
+
// Exempt canonical state or ref-retained only — nothing to reclaim.
|
|
1288
|
+
return { ...noop, keptCommits: commits.length };
|
|
1289
|
+
}
|
|
1290
|
+
if (verdict === "prunable") {
|
|
1291
|
+
// Only unreachable blobs (e.g. an external add that stageAllLocked
|
|
1292
|
+
// reset) — prune reclaims them without rewriting any history.
|
|
1293
|
+
await this.expireReflogsAndPruneLocked();
|
|
1294
|
+
log.info(
|
|
1295
|
+
{ workspaceDir: this.workspaceDir },
|
|
1296
|
+
"Pruned unreachable oversized blobs from workspace git",
|
|
1297
|
+
);
|
|
1298
|
+
return { ...noop, keptCommits: commits.length };
|
|
1299
|
+
}
|
|
1253
1300
|
}
|
|
1254
1301
|
|
|
1255
1302
|
// Squash a PREFIX of the chain so replay order stays consistent even if
|
|
1256
1303
|
// commit timestamps are not monotonic.
|
|
1257
|
-
const cutoffSec =
|
|
1258
|
-
Math.floor(Date.now() / 1000) - HISTORY_RETENTION_DAYS * 86400;
|
|
1304
|
+
const cutoffSec = Math.floor(Date.now() / 1000) - retentionDays * 86400;
|
|
1259
1305
|
let splitIdx = commits.findIndex((c) => c.committedAtSec >= cutoffSec);
|
|
1260
1306
|
if (splitIdx === -1) {
|
|
1261
1307
|
splitIdx = commits.length;
|
|
1262
1308
|
}
|
|
1263
1309
|
if (splitIdx === 0) {
|
|
1310
|
+
if (oversizedOids.size === 0) {
|
|
1311
|
+
// Forced run, but every commit is inside retention and there is
|
|
1312
|
+
// nothing to reclaim — no rewrite.
|
|
1313
|
+
return { ...noop, keptCommits: commits.length };
|
|
1314
|
+
}
|
|
1264
1315
|
// Main holds the blobs, but only in commits still within retention.
|
|
1265
1316
|
// A mixed case can also carry unreachable blobs — prune those now,
|
|
1266
1317
|
// and re-check in case they were all that remained actionable.
|
|
@@ -1279,7 +1330,7 @@ export class WorkspaceGitService {
|
|
|
1279
1330
|
// bloat until restart.
|
|
1280
1331
|
const oldestCommittedAtSec = commits[0]?.committedAtSec ?? cutoffSec;
|
|
1281
1332
|
const oldestAgesOutMs =
|
|
1282
|
-
(oldestCommittedAtSec +
|
|
1333
|
+
(oldestCommittedAtSec + retentionDays * 86400) * 1000 -
|
|
1283
1334
|
Date.now() +
|
|
1284
1335
|
60_000;
|
|
1285
1336
|
const retryAfterMs = Math.max(
|
|
@@ -1358,9 +1409,7 @@ export class WorkspaceGitService {
|
|
|
1358
1409
|
const oldestKeptSec =
|
|
1359
1410
|
kept[0]?.committedAtSec ?? Math.floor(Date.now() / 1000);
|
|
1360
1411
|
retryAfterMs = Math.max(
|
|
1361
|
-
(oldestKeptSec +
|
|
1362
|
-
Date.now() +
|
|
1363
|
-
60_000,
|
|
1412
|
+
(oldestKeptSec + retentionDays * 86400) * 1000 - Date.now() + 60_000,
|
|
1364
1413
|
HISTORY_COMPACTION_MIN_RETRY_MS,
|
|
1365
1414
|
);
|
|
1366
1415
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Repair the retired Fireworks MiniMax M2.5 model ID in workspace LLM config.
|
|
8
|
+
*
|
|
9
|
+
* Fireworks no longer serves `accounts/fireworks/models/minimax-m2p5`, so
|
|
10
|
+
* chat/completions calls fail with a 404 "Model not found, inaccessible,
|
|
11
|
+
* and/or not deployed". The ID was never an intent default — it was only
|
|
12
|
+
* reachable by picking it — but a config that picked it still pins it in
|
|
13
|
+
* `llm.default`, `llm.callSites.*`, and `llm.profiles.*`.
|
|
14
|
+
*
|
|
15
|
+
* Repair those leaves only on an exact match, replacing with
|
|
16
|
+
* `accounts/fireworks/models/minimax-m2p7`: the nearest live MiniMax entry
|
|
17
|
+
* (same 196K window, same 25K output cap, same per-token pricing), so the
|
|
18
|
+
* repaired pin keeps the model family the user chose. Deliberately not
|
|
19
|
+
* `minimax-m3`, which is the current Fireworks balanced-intent model —
|
|
20
|
+
* rewriting a hand-edited `custom-*` profile onto the template's model
|
|
21
|
+
* would make it read as unedited to `ensureByokDefaultProfiles`.
|
|
22
|
+
*
|
|
23
|
+
* Provider guard: the retired ID belongs to the `fireworks` provider and
|
|
24
|
+
* also appears in managed profiles stamped `provider: "vellum"` (which
|
|
25
|
+
* route Fireworks-account model IDs through the managed proxy). A fragment
|
|
26
|
+
* is repaired when its `provider` is `"fireworks"`, `"vellum"`, or absent;
|
|
27
|
+
* an explicit other provider (e.g. an `openai-compatible` endpoint serving
|
|
28
|
+
* a model by the same name) is left untouched.
|
|
29
|
+
*/
|
|
30
|
+
export const repairRetiredFireworksMinimaxModelIdMigration: WorkspaceMigration =
|
|
31
|
+
{
|
|
32
|
+
id: "137-repair-retired-fireworks-minimax-model-id",
|
|
33
|
+
description:
|
|
34
|
+
"Repair retired Fireworks accounts/fireworks/models/minimax-m2p5 model ID in workspace LLM config",
|
|
35
|
+
run(workspaceDir: string): void {
|
|
36
|
+
const configPath = join(workspaceDir, "config.json");
|
|
37
|
+
if (!existsSync(configPath)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Read outside the parse catch: a transient filesystem error (EIO,
|
|
42
|
+
// EACCES) must reach the runner so the migration retries, while
|
|
43
|
+
// malformed JSON is a permanent state this migration cannot repair.
|
|
44
|
+
const rawText = readFileSync(configPath, "utf-8");
|
|
45
|
+
|
|
46
|
+
let config: Record<string, unknown>;
|
|
47
|
+
try {
|
|
48
|
+
const raw = JSON.parse(rawText);
|
|
49
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
config = raw as Record<string, unknown>;
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const llm = readObject(config.llm);
|
|
58
|
+
if (llm === null) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let changed = false;
|
|
63
|
+
|
|
64
|
+
changed = repairFragment(readObject(llm.default)) || changed;
|
|
65
|
+
|
|
66
|
+
const callSites = readObject(llm.callSites);
|
|
67
|
+
if (callSites !== null) {
|
|
68
|
+
for (const rawConfig of Object.values(callSites)) {
|
|
69
|
+
changed = repairFragment(readObject(rawConfig)) || changed;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const profiles = readObject(llm.profiles);
|
|
74
|
+
if (profiles !== null) {
|
|
75
|
+
for (const rawProfile of Object.values(profiles)) {
|
|
76
|
+
changed = repairFragment(readObject(rawProfile)) || changed;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!changed) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Write-then-rename so an interrupted write cannot leave config.json
|
|
85
|
+
// truncated: a torn in-place write would parse as invalid JSON on the
|
|
86
|
+
// retry, which the catch above treats as "nothing to do", letting the
|
|
87
|
+
// runner checkpoint the migration as completed against a corrupt file.
|
|
88
|
+
const tmpPath = `${configPath}.migration-137.tmp`;
|
|
89
|
+
writeFileSync(tmpPath, JSON.stringify(config, null, 2) + "\n");
|
|
90
|
+
renameSync(tmpPath, configPath);
|
|
91
|
+
},
|
|
92
|
+
// The exact-match rewrite is idempotent, so a transient failure (full
|
|
93
|
+
// disk, I/O error) is safe to retry on later startups.
|
|
94
|
+
retryFailedCheckpoint: true,
|
|
95
|
+
down(_workspaceDir: string): void {
|
|
96
|
+
// Forward-only: reintroducing the retired model ID would break
|
|
97
|
+
// Fireworks calls.
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Helpers: self-contained per workspace migrations AGENTS.md
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
const RETIRED_MODEL_ID = "accounts/fireworks/models/minimax-m2p5";
|
|
106
|
+
const REPLACEMENT_MODEL_ID = "accounts/fireworks/models/minimax-m2p7";
|
|
107
|
+
const REPAIRABLE_PROVIDERS = new Set(["fireworks", "vellum"]);
|
|
108
|
+
|
|
109
|
+
function repairFragment(fragment: Record<string, unknown> | null): boolean {
|
|
110
|
+
if (fragment === null) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
if (fragment.model !== RETIRED_MODEL_ID) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (
|
|
117
|
+
fragment.provider !== undefined &&
|
|
118
|
+
!REPAIRABLE_PROVIDERS.has(fragment.provider as string)
|
|
119
|
+
) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
fragment.model = REPLACEMENT_MODEL_ID;
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
127
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return value as Record<string, unknown>;
|
|
131
|
+
}
|