@vellumai/assistant 0.12.5 → 0.12.6-dev.202609292019.a6f6d85
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/.env.example +2 -0
- package/ARCHITECTURE.md +23 -0
- package/docs/automatic-done.md +32 -0
- package/docs/desktop-browser-cli.md +3 -2
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/mcp-oauth.test.ts +53 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/mcp-oauth.ts +60 -0
- package/node_modules/@vellumai/environments/src/shell.test.ts +13 -1
- package/node_modules/@vellumai/environments/src/shell.ts +22 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/mcp-oauth.test.ts +53 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/mcp-oauth.ts +60 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/status-contracts.test.ts +39 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +25 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/mcp-oauth.test.ts +53 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/mcp-oauth.ts +60 -0
- package/openapi.yaml +270 -10
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +76 -0
- package/src/__tests__/anthropic-provider.test.ts +2 -0
- package/src/__tests__/byok-default-profile-ensure.test.ts +7 -0
- package/src/__tests__/config-get-vision-flag.test.ts +1 -1
- package/src/__tests__/config-loader-validation-reset-notice.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +160 -154
- package/src/__tests__/conversation-evictor.test.ts +54 -0
- package/src/__tests__/conversation-pairing.test.ts +112 -0
- package/src/__tests__/document-append-idempotency.test.ts +13 -0
- package/src/__tests__/document-create-dedupe.test.ts +13 -0
- package/src/__tests__/document-find-replace.test.ts +13 -0
- package/src/__tests__/document-revision-history.test.ts +390 -0
- package/src/__tests__/document-revision.test.ts +425 -0
- package/src/__tests__/document-tool-security.test.ts +13 -0
- package/src/__tests__/document-update-default-surface.test.ts +13 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +270 -0
- package/src/__tests__/gateway-flag-listener.test.ts +59 -6
- package/src/__tests__/headless-browser-navigate.test.ts +20 -30
- package/src/__tests__/host-cu-proxy.test.ts +79 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +14 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -2
- package/src/__tests__/identity-routes.test.ts +4 -3
- package/src/__tests__/llm-catalog-parity.test.ts +4 -4
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/notification-platform-adapter.test.ts +83 -1
- package/src/__tests__/oauth2-gateway-transport.test.ts +2 -0
- package/src/__tests__/openai-provider.test.ts +11 -11
- package/src/__tests__/pricing.test.ts +11 -0
- package/src/__tests__/public-ingress-urls.test.ts +26 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +47 -0
- package/src/__tests__/usage-attribution.test.ts +31 -0
- package/src/__tests__/workspace-migration-133-collapse-provider-connections.test.ts +3 -3
- package/src/__tests__/workspace-migration-160-repair-retired-fireworks-model-ids.test.ts +262 -0
- package/src/__tests__/workspace-migration-161-repair-retired-fireworks-glm-5p2-model-id.test.ts +233 -0
- package/src/acp/agent-process.ts +6 -1
- package/src/acp/client-handler.ts +6 -1
- package/src/agent/loop.ts +29 -6
- package/src/api/events/document-editor-show.ts +5 -0
- package/src/api/events/document-editor-update.ts +10 -0
- package/src/api/events/tool-result.ts +1 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +54 -0
- package/src/calls/channel-admission-reader.ts +15 -9
- package/src/calls/twilio-provider.ts +14 -31
- package/src/calls/voice-session-bridge.ts +18 -1
- package/src/cli/commands/browser.ts +1 -2
- package/src/cli/lib/__tests__/plugin-artifact.test.ts +23 -0
- package/src/cli/lib/__tests__/plugin-catalog-visibility.test.ts +2 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +16 -0
- package/src/cli/lib/bundled-marketplace.json +41 -2
- package/src/cli/lib/inspect-plugin.ts +15 -15
- package/src/cli/lib/list-installed-plugins.ts +29 -28
- package/src/cli/lib/plugin-artifact.ts +74 -63
- package/src/cli/lib/plugin-catalog-visibility.ts +1 -0
- package/src/cli/lib/plugin-details.ts +27 -42
- package/src/cli/lib/plugin-marketplace.ts +6 -8
- package/src/cli/lib/plugin-surfaces.ts +8 -7
- package/src/cli.ts +1 -3
- package/src/config/__tests__/chat-settings.test.ts +121 -0
- package/src/config/assistant-feature-flags.ts +28 -23
- package/src/config/bundled-skills/computer-use/SKILL.md +20 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +11 -11
- package/src/config/chat-settings.ts +100 -0
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/feature-flag-cache.ts +7 -25
- package/src/config/feature-flag-registry.json +1 -9
- package/src/config/loader.ts +5 -1
- package/src/config/profile-text-generation.ts +25 -21
- package/src/config/schemas/conversations.ts +14 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/notifications.ts +8 -1
- package/src/contacts/gateway-channel-read.ts +1 -1
- package/src/conversations/__tests__/auto-archive-activity.test.ts +136 -0
- package/src/conversations/__tests__/auto-archive.test.ts +304 -0
- package/src/conversations/auto-archive-activity.ts +61 -0
- package/src/conversations/auto-archive.ts +201 -0
- package/src/daemon/computer-use-observation.test.ts +81 -0
- package/src/daemon/computer-use-observation.ts +23 -0
- package/src/daemon/conversation-agent-loop.ts +11 -6
- package/src/daemon/conversation-evictor.ts +50 -16
- package/src/daemon/doordash-steps.ts +1 -3
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +43 -1
- package/src/daemon/handlers/__tests__/config-channels.test.ts +1 -1
- package/src/daemon/handlers/config-a2a.ts +75 -2
- package/src/daemon/host-cu-proxy.ts +34 -3
- package/src/daemon/lifecycle.ts +15 -2
- package/src/daemon/shutdown-handlers.ts +3 -0
- package/src/daemon/turn-finalization.ts +4 -0
- package/src/desktop/desktop-browser-endpoint.ts +11 -2
- package/src/desktop/desktop-chrome-policy.test.ts +1 -0
- package/src/desktop/desktop-chrome-policy.ts +7 -1
- package/src/desktop/desktop-computer-use.test.ts +14 -4
- package/src/desktop/desktop-session-manager.ts +5 -3
- package/src/documents/document-revisions-store.ts +153 -0
- package/src/documents/document-store.ts +471 -133
- package/src/followups/followup-store.ts +0 -4
- package/src/inbound/__tests__/oauth-callback-url.test.ts +25 -2
- package/src/inbound/oauth-callback-url.ts +30 -1
- package/src/inbound/public-ingress-urls.ts +12 -2
- package/src/ipc/gateway-client.test.ts +40 -0
- package/src/ipc/gateway-client.ts +12 -29
- package/src/ipc/gateway-flag-listener.ts +7 -10
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +71 -0
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +83 -0
- package/src/live-voice/__tests__/protocol.test.ts +77 -0
- package/src/live-voice/__tests__/share-targets.test.ts +163 -0
- package/src/live-voice/live-voice-session.ts +23 -6
- package/src/live-voice/protocol.ts +22 -0
- package/src/live-voice/share-targets.ts +225 -0
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +144 -3
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +2 -0
- package/src/mcp/client.ts +1 -19
- package/src/mcp/mcp-oauth-provider.ts +66 -49
- package/src/media/openrouter-image-service.ts +39 -22
- package/src/monitoring/__tests__/oom-inheritance-sweep.test.ts +86 -0
- package/src/monitoring/__tests__/oom-kill-reporter.test.ts +374 -0
- package/src/monitoring/control.ts +2 -1
- package/src/monitoring/oom-inheritance-sweep.ts +96 -0
- package/src/monitoring/oom-kill-reporter.ts +469 -0
- package/src/monitoring/resource-sampler.ts +30 -0
- package/src/notifications/README.md +53 -4
- package/src/notifications/__tests__/assistant-initiated-thread.test.ts +254 -0
- package/src/notifications/__tests__/broadcaster.test.ts +558 -6
- package/src/notifications/__tests__/completion-policy.test.ts +37 -0
- package/src/notifications/__tests__/from-me-alert-integration.test.ts +192 -0
- package/src/notifications/adapters/platform.ts +14 -0
- package/src/notifications/assistant-initiated-thread.ts +101 -0
- package/src/notifications/broadcaster.ts +94 -16
- package/src/notifications/chat-reply-policy.ts +11 -0
- package/src/notifications/completion-policy.ts +12 -2
- package/src/notifications/conversation-pairing.ts +15 -70
- package/src/notifications/emit-signal.ts +34 -3
- package/src/notifications/types.ts +2 -0
- package/src/oauth/connect-orchestrator.ts +1 -2
- package/src/persistence/__tests__/conversation-auto-archive.test.ts +330 -0
- package/src/persistence/conversation-auto-archive.ts +170 -0
- package/src/persistence/conversation-crud.ts +2 -1
- package/src/persistence/conversation-queries.ts +15 -8
- package/src/persistence/embeddings/embed.test.ts +96 -0
- package/src/persistence/embeddings/embed.ts +20 -2
- package/src/persistence/embeddings/embedding-gemini.test.ts +39 -3
- package/src/persistence/embeddings/embedding-gemini.ts +39 -1
- package/src/persistence/embeddings/embedding-local.ts +6 -0
- package/src/persistence/embeddings/qdrant-manager.ts +5 -0
- package/src/persistence/job-utils.ts +10 -0
- package/src/persistence/migrations/384-add-document-revision.test.ts +83 -0
- package/src/persistence/migrations/384-add-document-revision.ts +21 -0
- package/src/persistence/migrations/385-create-document-revisions.test.ts +67 -0
- package/src/persistence/migrations/385-create-document-revisions.ts +28 -0
- package/src/persistence/migrations/386-conversations-last-reopened-at.ts +10 -0
- package/src/persistence/migrations/__tests__/386-conversations-last-reopened-at.test.ts +32 -0
- package/src/persistence/schema/conversations.ts +1 -0
- package/src/persistence/schema/documents.ts +20 -0
- package/src/persistence/steps.ts +6 -0
- package/src/platform/managed-speech.ts +42 -46
- package/src/plugin-api/vision-support.test.ts +21 -21
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +11 -6
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +1 -1
- package/src/providers/__tests__/search-provider-catalog.test.ts +8 -0
- package/src/providers/anthropic/client.ts +1 -1
- package/src/providers/fireworks/client.test.ts +168 -0
- package/src/providers/fireworks/client.ts +24 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/ionet/client.test.ts +143 -0
- package/src/providers/ionet/client.ts +37 -0
- package/src/providers/model-catalog.ts +141 -84
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +23 -1
- package/src/providers/retry.ts +56 -4
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/types.ts +10 -2
- package/src/providers/usage-tracking.ts +5 -3
- package/src/runtime/assistant-event-hub.ts +23 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +0 -7
- package/src/runtime/auth/__tests__/route-policy.test.ts +1 -1
- package/src/runtime/channel-retry-sweep.ts +1 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +35 -10
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +48 -0
- package/src/runtime/migrations/vbundle-builder.ts +19 -3
- package/src/runtime/migrations/vbundle-streaming-importer.ts +14 -19
- package/src/runtime/migrations/vbundle-streaming-validator.ts +14 -7
- package/src/runtime/migrations/vbundle-validator.ts +54 -1
- package/src/runtime/pending-interactions.ts +20 -2
- package/src/runtime/routes/__tests__/contact-routes.test.ts +5 -3
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +36 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +375 -2
- package/src/runtime/routes/__tests__/inference-send-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +12 -0
- package/src/runtime/routes/contact-routes.ts +2 -2
- package/src/runtime/routes/conversation-list-routes.ts +10 -2
- package/src/runtime/routes/conversation-query-routes.ts +48 -10
- package/src/runtime/routes/documents-routes.ts +185 -47
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -0
- package/src/runtime/routes/host-bash-routes.ts +1 -0
- package/src/runtime/routes/host-browser-routes.ts +15 -0
- package/src/runtime/routes/host-cu-routes.ts +4 -1
- package/src/runtime/routes/host-file-routes.ts +1 -0
- package/src/runtime/routes/host-proxy-result-binding.test.ts +83 -0
- package/src/runtime/routes/host-proxy-result-binding.ts +25 -0
- package/src/runtime/routes/host-transfer-routes.ts +1 -0
- package/src/runtime/routes/identity-routes.ts +3 -3
- package/src/runtime/routes/integrations/a2a.ts +4 -1
- package/src/runtime/routes/migration-routes.ts +3 -1
- package/src/runtime/routes/notification-routes.ts +1 -2
- package/src/runtime/routes/ui-snapshot-routes.test.ts +1 -0
- package/src/runtime/routes/user-route-dispatcher.ts +5 -1
- package/src/runtime/verification-templates.ts +1 -2
- package/src/sequence/analytics.ts +0 -4
- package/src/sequence/engine.ts +1 -11
- package/src/sequence/guardrails.ts +1 -6
- package/src/sequence/importer.ts +0 -8
- package/src/sequence/store.ts +0 -10
- package/src/signals/user-message.ts +0 -6
- package/src/skills/catalog-install.ts +52 -23
- package/src/tools/browser/browser-execution.ts +20 -23
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +1 -3
- package/src/tools/document/document-tool.ts +13 -11
- package/src/tools/executor.ts +1 -2
- package/src/tools/host-terminal/host-shell.ts +4 -2
- package/src/tools/network/__tests__/web-search.test.ts +105 -0
- package/src/tools/network/web-fetch.ts +2 -4
- package/src/tools/network/web-search.ts +239 -12
- package/src/tools/shared/filesystem/format-diff.ts +1 -2
- package/src/tools/shared/shell-output.test.ts +42 -0
- package/src/tools/shared/shell-output.ts +27 -4
- package/src/tools/terminal/shell.ts +3 -3
- package/src/tools/ui-surface/visual-validation.ts +1 -2
- package/src/usage/attribution.ts +18 -1
- package/src/util/__tests__/oom-priority.test.ts +55 -0
- package/src/util/__tests__/worker-memory.test.ts +16 -0
- package/src/util/debounce.ts +0 -4
- package/src/util/oom-priority.ts +79 -0
- package/src/util/platform.ts +0 -2
- package/src/util/plugin-manifest.ts +5 -7
- package/src/util/pricing.ts +25 -0
- package/src/util/worker-memory.ts +9 -3
- package/src/util/worker-process.ts +8 -0
- package/src/workspace/byok-default-profile-ensure.ts +11 -0
- package/src/workspace/hatched-date.ts +11 -4
- package/src/workspace/migrations/160-repair-retired-fireworks-model-ids.ts +209 -0
- package/src/workspace/migrations/161-repair-retired-fireworks-glm-5p2-model-id.ts +197 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
rmSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { Database } from "bun:sqlite";
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
12
|
+
|
|
13
|
+
import { repairRetiredFireworksModelIdsMigration } from "../workspace/migrations/160-repair-retired-fireworks-model-ids.js";
|
|
14
|
+
import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
|
|
15
|
+
import { assertNotLiveDb } from "./assert-not-live-db.js";
|
|
16
|
+
|
|
17
|
+
const STALE = "accounts/fireworks/models/deepseek-v4-flash-0731";
|
|
18
|
+
const REPLACEMENT = "accounts/fireworks/models/deepseek-v4p1-flash";
|
|
19
|
+
|
|
20
|
+
let workspaceDir: string;
|
|
21
|
+
|
|
22
|
+
function freshWorkspace(): void {
|
|
23
|
+
workspaceDir = join(
|
|
24
|
+
tmpdir(),
|
|
25
|
+
`vellum-migration-160-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
26
|
+
);
|
|
27
|
+
mkdirSync(workspaceDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function writeConfig(data: Record<string, unknown>): void {
|
|
31
|
+
writeFileSync(
|
|
32
|
+
join(workspaceDir, "config.json"),
|
|
33
|
+
JSON.stringify(data, null, 2) + "\n",
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readConfig(): Record<string, unknown> {
|
|
38
|
+
return JSON.parse(readFileSync(join(workspaceDir, "config.json"), "utf-8"));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function seedRows(rows: Array<{ name: string; provider: string }>): void {
|
|
42
|
+
mkdirSync(join(workspaceDir, "data", "db"), { recursive: true });
|
|
43
|
+
const db = new Database(join(workspaceDir, "data", "db", "assistant.db"));
|
|
44
|
+
db.run(`CREATE TABLE IF NOT EXISTS provider_connections (
|
|
45
|
+
name TEXT PRIMARY KEY,
|
|
46
|
+
provider TEXT NOT NULL,
|
|
47
|
+
auth TEXT NOT NULL,
|
|
48
|
+
created_at INTEGER NOT NULL,
|
|
49
|
+
updated_at INTEGER NOT NULL
|
|
50
|
+
)`);
|
|
51
|
+
for (const row of rows) {
|
|
52
|
+
db.query(
|
|
53
|
+
`INSERT INTO provider_connections (name, provider, auth, created_at, updated_at) VALUES (?, ?, '{"type":"api_key"}', 1, 1)`,
|
|
54
|
+
).run(row.name, row.provider);
|
|
55
|
+
}
|
|
56
|
+
db.close();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
freshWorkspace();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
if (existsSync(workspaceDir)) {
|
|
65
|
+
assertNotLiveDb(workspaceDir);
|
|
66
|
+
rmSync(workspaceDir, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("160-repair-retired-fireworks-model-ids migration", () => {
|
|
71
|
+
test("has correct migration id and is registered", () => {
|
|
72
|
+
expect(repairRetiredFireworksModelIdsMigration.id).toBe(
|
|
73
|
+
"160-repair-retired-fireworks-model-ids",
|
|
74
|
+
);
|
|
75
|
+
expect(WORKSPACE_MIGRATIONS.map((m) => m.id)).toContain(
|
|
76
|
+
"160-repair-retired-fireworks-model-ids",
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("repairs the stale ID in default, call sites, and profiles", () => {
|
|
81
|
+
writeConfig({
|
|
82
|
+
llm: {
|
|
83
|
+
default: { provider: "fireworks", model: STALE },
|
|
84
|
+
callSites: {
|
|
85
|
+
recall: { model: STALE, maxTokens: 4096 },
|
|
86
|
+
heartbeat: { model: `${STALE}-tuned` },
|
|
87
|
+
malformed: STALE,
|
|
88
|
+
},
|
|
89
|
+
profiles: {
|
|
90
|
+
"cost-optimized": { provider: "vellum", model: STALE },
|
|
91
|
+
legacy: { model: STALE },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
97
|
+
|
|
98
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
99
|
+
expect(llm.default.model).toBe(REPLACEMENT);
|
|
100
|
+
expect(llm.callSites.recall.model).toBe(REPLACEMENT);
|
|
101
|
+
expect(llm.callSites.recall.maxTokens).toBe(4096);
|
|
102
|
+
// Non-exact matches and malformed leaves are untouched.
|
|
103
|
+
expect(llm.callSites.heartbeat.model).toBe(`${STALE}-tuned`);
|
|
104
|
+
expect(llm.callSites.malformed).toBe(STALE);
|
|
105
|
+
// Managed profiles stamped provider "vellum" carry Fireworks model IDs.
|
|
106
|
+
expect(llm.profiles["cost-optimized"].model).toBe(REPLACEMENT);
|
|
107
|
+
expect(llm.profiles.legacy.model).toBe(REPLACEMENT);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test.each([
|
|
111
|
+
[
|
|
112
|
+
"accounts/fireworks/models/deepseek-v4-pro-0813",
|
|
113
|
+
"accounts/fireworks/models/deepseek-v4p1-flash",
|
|
114
|
+
],
|
|
115
|
+
[
|
|
116
|
+
"accounts/fireworks/models/kimi-k2p6",
|
|
117
|
+
"accounts/fireworks/models/kimi-k3",
|
|
118
|
+
],
|
|
119
|
+
])("repairs %s to %s", (stale, replacement) => {
|
|
120
|
+
writeConfig({
|
|
121
|
+
llm: {
|
|
122
|
+
default: { provider: "fireworks", model: stale },
|
|
123
|
+
profiles: {
|
|
124
|
+
managed: { provider: "vellum", model: stale },
|
|
125
|
+
other: { provider: "openai-compatible", model: stale },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
131
|
+
|
|
132
|
+
const llm = readConfig().llm as Record<string, unknown>;
|
|
133
|
+
const profiles = llm.profiles as Record<string, Record<string, unknown>>;
|
|
134
|
+
expect((llm.default as Record<string, unknown>).model).toBe(replacement);
|
|
135
|
+
expect(profiles.managed.model).toBe(replacement);
|
|
136
|
+
expect(profiles.other.model).toBe(stale);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("repairs entry-bound fragments whose row kind is fireworks or vellum", () => {
|
|
140
|
+
seedRows([
|
|
141
|
+
{ name: "my-fireworks", provider: "fireworks" },
|
|
142
|
+
{ name: "managed-alt", provider: "vellum" },
|
|
143
|
+
]);
|
|
144
|
+
writeConfig({
|
|
145
|
+
llm: {
|
|
146
|
+
profiles: {
|
|
147
|
+
bound: { provider: "my-fireworks", model: STALE },
|
|
148
|
+
managed: { provider: "managed-alt", model: STALE },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
154
|
+
|
|
155
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
156
|
+
expect(llm.profiles.bound.model).toBe(REPLACEMENT);
|
|
157
|
+
expect(llm.profiles.managed.model).toBe(REPLACEMENT);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("leaves fragments with an explicit other provider untouched", () => {
|
|
161
|
+
seedRows([{ name: "byo-compat", provider: "openai-compatible" }]);
|
|
162
|
+
writeConfig({
|
|
163
|
+
llm: {
|
|
164
|
+
default: { provider: "openai-compatible", model: STALE },
|
|
165
|
+
profiles: {
|
|
166
|
+
byo: { provider: "openai-compatible", model: STALE },
|
|
167
|
+
// Entry-bound profile whose row kind is not repairable.
|
|
168
|
+
compatBound: { provider: "byo-compat", model: STALE },
|
|
169
|
+
// Entry name with no row: dangling, so nothing proves it is a
|
|
170
|
+
// fireworks-kind route.
|
|
171
|
+
dangling: { provider: "ghost", model: STALE },
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
177
|
+
|
|
178
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
179
|
+
expect(llm.default.model).toBe(STALE);
|
|
180
|
+
expect(llm.profiles.byo.model).toBe(STALE);
|
|
181
|
+
expect(llm.profiles.compatBound.model).toBe(STALE);
|
|
182
|
+
expect(llm.profiles.dangling.model).toBe(STALE);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("leaves entry-name providers untouched when no DB file exists", () => {
|
|
186
|
+
writeConfig({
|
|
187
|
+
llm: {
|
|
188
|
+
profiles: { bound: { provider: "my-fireworks", model: STALE } },
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
193
|
+
|
|
194
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
195
|
+
expect(llm.profiles.bound.model).toBe(STALE);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("throws when an entry-name provider needs rows and the DB is unreadable", () => {
|
|
199
|
+
// A DB file without the provider_connections table is unqueryable, so
|
|
200
|
+
// the run must fail (and retry later) instead of skipping the profile.
|
|
201
|
+
mkdirSync(join(workspaceDir, "data", "db"), { recursive: true });
|
|
202
|
+
writeFileSync(join(workspaceDir, "data", "db", "assistant.db"), "");
|
|
203
|
+
writeConfig({
|
|
204
|
+
llm: {
|
|
205
|
+
profiles: { bound: { provider: "my-fireworks", model: STALE } },
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
expect(() =>
|
|
210
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir),
|
|
211
|
+
).toThrow();
|
|
212
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
213
|
+
expect(llm.profiles.bound.model).toBe(STALE);
|
|
214
|
+
|
|
215
|
+
// Vendor and absent providers never need the rows, so the same broken
|
|
216
|
+
// DB does not block their repair.
|
|
217
|
+
writeConfig({
|
|
218
|
+
llm: {
|
|
219
|
+
default: { provider: "fireworks", model: STALE },
|
|
220
|
+
profiles: { legacy: { model: STALE } },
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
224
|
+
const repaired = readConfig().llm as Record<string, any>;
|
|
225
|
+
expect(repaired.default.model).toBe(REPLACEMENT);
|
|
226
|
+
expect(repaired.profiles.legacy.model).toBe(REPLACEMENT);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("is idempotent and a no-op without the stale ID", () => {
|
|
230
|
+
writeConfig({
|
|
231
|
+
llm: {
|
|
232
|
+
default: { provider: "fireworks", model: STALE },
|
|
233
|
+
profiles: { fine: { provider: "fireworks", model: REPLACEMENT } },
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
238
|
+
const first = readConfig();
|
|
239
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
240
|
+
expect(readConfig()).toEqual(first);
|
|
241
|
+
|
|
242
|
+
const llm = first.llm as Record<string, any>;
|
|
243
|
+
expect(llm.default.model).toBe(REPLACEMENT);
|
|
244
|
+
expect(llm.profiles.fine.model).toBe(REPLACEMENT);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("handles missing config, missing llm block, and invalid JSON", () => {
|
|
248
|
+
// No config.json at all.
|
|
249
|
+
expect(() =>
|
|
250
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir),
|
|
251
|
+
).not.toThrow();
|
|
252
|
+
|
|
253
|
+
writeConfig({ theme: "dark" });
|
|
254
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir);
|
|
255
|
+
expect(readConfig()).toEqual({ theme: "dark" });
|
|
256
|
+
|
|
257
|
+
writeFileSync(join(workspaceDir, "config.json"), "{not json");
|
|
258
|
+
expect(() =>
|
|
259
|
+
repairRetiredFireworksModelIdsMigration.run(workspaceDir),
|
|
260
|
+
).not.toThrow();
|
|
261
|
+
});
|
|
262
|
+
});
|
package/src/__tests__/workspace-migration-161-repair-retired-fireworks-glm-5p2-model-id.test.ts
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
rmSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { Database } from "bun:sqlite";
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
12
|
+
|
|
13
|
+
import { repairRetiredFireworksGlm5p2ModelIdMigration } from "../workspace/migrations/161-repair-retired-fireworks-glm-5p2-model-id.js";
|
|
14
|
+
import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
|
|
15
|
+
import { assertNotLiveDb } from "./assert-not-live-db.js";
|
|
16
|
+
|
|
17
|
+
const STALE = "accounts/fireworks/models/glm-5p2";
|
|
18
|
+
const REPLACEMENT = "accounts/fireworks/models/glm-5p3";
|
|
19
|
+
|
|
20
|
+
let workspaceDir: string;
|
|
21
|
+
|
|
22
|
+
function freshWorkspace(): void {
|
|
23
|
+
workspaceDir = join(
|
|
24
|
+
tmpdir(),
|
|
25
|
+
`vellum-migration-161-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
26
|
+
);
|
|
27
|
+
mkdirSync(workspaceDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function writeConfig(data: Record<string, unknown>): void {
|
|
31
|
+
writeFileSync(
|
|
32
|
+
join(workspaceDir, "config.json"),
|
|
33
|
+
JSON.stringify(data, null, 2) + "\n",
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readConfig(): Record<string, unknown> {
|
|
38
|
+
return JSON.parse(readFileSync(join(workspaceDir, "config.json"), "utf-8"));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function seedRows(rows: Array<{ name: string; provider: string }>): void {
|
|
42
|
+
mkdirSync(join(workspaceDir, "data", "db"), { recursive: true });
|
|
43
|
+
const db = new Database(join(workspaceDir, "data", "db", "assistant.db"));
|
|
44
|
+
db.run(`CREATE TABLE IF NOT EXISTS provider_connections (
|
|
45
|
+
name TEXT PRIMARY KEY,
|
|
46
|
+
provider TEXT NOT NULL,
|
|
47
|
+
auth TEXT NOT NULL,
|
|
48
|
+
created_at INTEGER NOT NULL,
|
|
49
|
+
updated_at INTEGER NOT NULL
|
|
50
|
+
)`);
|
|
51
|
+
for (const row of rows) {
|
|
52
|
+
db.query(
|
|
53
|
+
`INSERT INTO provider_connections (name, provider, auth, created_at, updated_at) VALUES (?, ?, '{"type":"api_key"}', 1, 1)`,
|
|
54
|
+
).run(row.name, row.provider);
|
|
55
|
+
}
|
|
56
|
+
db.close();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
freshWorkspace();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
if (existsSync(workspaceDir)) {
|
|
65
|
+
assertNotLiveDb(workspaceDir);
|
|
66
|
+
rmSync(workspaceDir, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("161-repair-retired-fireworks-glm-5p2-model-id migration", () => {
|
|
71
|
+
test("has correct migration id and is registered", () => {
|
|
72
|
+
expect(repairRetiredFireworksGlm5p2ModelIdMigration.id).toBe(
|
|
73
|
+
"161-repair-retired-fireworks-glm-5p2-model-id",
|
|
74
|
+
);
|
|
75
|
+
expect(WORKSPACE_MIGRATIONS.map((m) => m.id)).toContain(
|
|
76
|
+
"161-repair-retired-fireworks-glm-5p2-model-id",
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("repairs the stale ID in default, call sites, and profiles", () => {
|
|
81
|
+
writeConfig({
|
|
82
|
+
llm: {
|
|
83
|
+
default: { provider: "fireworks", model: STALE },
|
|
84
|
+
callSites: {
|
|
85
|
+
recall: { model: STALE, maxTokens: 4096 },
|
|
86
|
+
heartbeat: { model: `${STALE}-tuned` },
|
|
87
|
+
malformed: STALE,
|
|
88
|
+
},
|
|
89
|
+
profiles: {
|
|
90
|
+
"cost-optimized": { provider: "vellum", model: STALE },
|
|
91
|
+
legacy: { model: STALE },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
97
|
+
|
|
98
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
99
|
+
expect(llm.default.model).toBe(REPLACEMENT);
|
|
100
|
+
expect(llm.callSites.recall.model).toBe(REPLACEMENT);
|
|
101
|
+
expect(llm.callSites.recall.maxTokens).toBe(4096);
|
|
102
|
+
// Non-exact matches and malformed leaves are untouched.
|
|
103
|
+
expect(llm.callSites.heartbeat.model).toBe(`${STALE}-tuned`);
|
|
104
|
+
expect(llm.callSites.malformed).toBe(STALE);
|
|
105
|
+
// Managed profiles stamped provider "vellum" carry Fireworks model IDs.
|
|
106
|
+
expect(llm.profiles["cost-optimized"].model).toBe(REPLACEMENT);
|
|
107
|
+
expect(llm.profiles.legacy.model).toBe(REPLACEMENT);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("repairs entry-bound fragments whose row kind is fireworks or vellum", () => {
|
|
111
|
+
seedRows([
|
|
112
|
+
{ name: "my-fireworks", provider: "fireworks" },
|
|
113
|
+
{ name: "managed-alt", provider: "vellum" },
|
|
114
|
+
]);
|
|
115
|
+
writeConfig({
|
|
116
|
+
llm: {
|
|
117
|
+
profiles: {
|
|
118
|
+
bound: { provider: "my-fireworks", model: STALE },
|
|
119
|
+
managed: { provider: "managed-alt", model: STALE },
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
125
|
+
|
|
126
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
127
|
+
expect(llm.profiles.bound.model).toBe(REPLACEMENT);
|
|
128
|
+
expect(llm.profiles.managed.model).toBe(REPLACEMENT);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("leaves fragments with an explicit other provider untouched", () => {
|
|
132
|
+
seedRows([{ name: "byo-compat", provider: "openai-compatible" }]);
|
|
133
|
+
writeConfig({
|
|
134
|
+
llm: {
|
|
135
|
+
default: { provider: "openai-compatible", model: STALE },
|
|
136
|
+
profiles: {
|
|
137
|
+
byo: { provider: "openai-compatible", model: STALE },
|
|
138
|
+
// Entry-bound profile whose row kind is not repairable.
|
|
139
|
+
compatBound: { provider: "byo-compat", model: STALE },
|
|
140
|
+
// Entry name with no row: dangling, so nothing proves it is a
|
|
141
|
+
// fireworks-kind route.
|
|
142
|
+
dangling: { provider: "ghost", model: STALE },
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
148
|
+
|
|
149
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
150
|
+
expect(llm.default.model).toBe(STALE);
|
|
151
|
+
expect(llm.profiles.byo.model).toBe(STALE);
|
|
152
|
+
expect(llm.profiles.compatBound.model).toBe(STALE);
|
|
153
|
+
expect(llm.profiles.dangling.model).toBe(STALE);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("leaves entry-name providers untouched when no DB file exists", () => {
|
|
157
|
+
writeConfig({
|
|
158
|
+
llm: {
|
|
159
|
+
profiles: { bound: { provider: "my-fireworks", model: STALE } },
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
164
|
+
|
|
165
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
166
|
+
expect(llm.profiles.bound.model).toBe(STALE);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("throws when an entry-name provider needs rows and the DB is unreadable", () => {
|
|
170
|
+
// A DB file without the provider_connections table is unqueryable, so
|
|
171
|
+
// the run must fail (and retry later) instead of skipping the profile.
|
|
172
|
+
mkdirSync(join(workspaceDir, "data", "db"), { recursive: true });
|
|
173
|
+
writeFileSync(join(workspaceDir, "data", "db", "assistant.db"), "");
|
|
174
|
+
writeConfig({
|
|
175
|
+
llm: {
|
|
176
|
+
profiles: { bound: { provider: "my-fireworks", model: STALE } },
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(() =>
|
|
181
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir),
|
|
182
|
+
).toThrow();
|
|
183
|
+
const llm = readConfig().llm as Record<string, any>;
|
|
184
|
+
expect(llm.profiles.bound.model).toBe(STALE);
|
|
185
|
+
|
|
186
|
+
// Vendor and absent providers never need the rows, so the same broken
|
|
187
|
+
// DB does not block their repair.
|
|
188
|
+
writeConfig({
|
|
189
|
+
llm: {
|
|
190
|
+
default: { provider: "fireworks", model: STALE },
|
|
191
|
+
profiles: { legacy: { model: STALE } },
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
195
|
+
const repaired = readConfig().llm as Record<string, any>;
|
|
196
|
+
expect(repaired.default.model).toBe(REPLACEMENT);
|
|
197
|
+
expect(repaired.profiles.legacy.model).toBe(REPLACEMENT);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("is idempotent and a no-op without the stale ID", () => {
|
|
201
|
+
writeConfig({
|
|
202
|
+
llm: {
|
|
203
|
+
default: { provider: "fireworks", model: STALE },
|
|
204
|
+
profiles: { fine: { provider: "fireworks", model: REPLACEMENT } },
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
209
|
+
const first = readConfig();
|
|
210
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
211
|
+
expect(readConfig()).toEqual(first);
|
|
212
|
+
|
|
213
|
+
const llm = first.llm as Record<string, any>;
|
|
214
|
+
expect(llm.default.model).toBe(REPLACEMENT);
|
|
215
|
+
expect(llm.profiles.fine.model).toBe(REPLACEMENT);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("handles missing config, missing llm block, and invalid JSON", () => {
|
|
219
|
+
// No config.json at all.
|
|
220
|
+
expect(() =>
|
|
221
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir),
|
|
222
|
+
).not.toThrow();
|
|
223
|
+
|
|
224
|
+
writeConfig({ theme: "dark" });
|
|
225
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir);
|
|
226
|
+
expect(readConfig()).toEqual({ theme: "dark" });
|
|
227
|
+
|
|
228
|
+
writeFileSync(join(workspaceDir, "config.json"), "{not json");
|
|
229
|
+
expect(() =>
|
|
230
|
+
repairRetiredFireworksGlm5p2ModelIdMigration.run(workspaceDir),
|
|
231
|
+
).not.toThrow();
|
|
232
|
+
});
|
|
233
|
+
});
|
package/src/acp/agent-process.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
import * as acp from "@agentclientprotocol/sdk";
|
|
26
26
|
|
|
27
27
|
import { getLogger } from "../util/logger.js";
|
|
28
|
+
import { CHILD_OOM_SCORE_ADJ, withOomScoreAdj } from "../util/oom-priority.js";
|
|
28
29
|
import { safeStringSlice } from "../util/unicode.js";
|
|
29
30
|
import {
|
|
30
31
|
AcpAuthRequiredError,
|
|
@@ -110,7 +111,11 @@ export class AcpAgentProcess {
|
|
|
110
111
|
);
|
|
111
112
|
|
|
112
113
|
this.spawnedEnv = { ...process.env, ...this.config.env };
|
|
113
|
-
|
|
114
|
+
const [command, ...args] = withOomScoreAdj(
|
|
115
|
+
[this.config.command, ...this.config.args],
|
|
116
|
+
CHILD_OOM_SCORE_ADJ,
|
|
117
|
+
);
|
|
118
|
+
this.proc = spawn(command, args, {
|
|
114
119
|
cwd,
|
|
115
120
|
stdio: ["pipe", "pipe", "pipe"],
|
|
116
121
|
env: this.spawnedEnv,
|
|
@@ -38,6 +38,7 @@ import { redactJsonStringLeaves } from "../security/redact-json.js";
|
|
|
38
38
|
import { redactSensitiveFields } from "../security/redaction.js";
|
|
39
39
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
40
40
|
import { getLogger } from "../util/logger.js";
|
|
41
|
+
import { CHILD_OOM_SCORE_ADJ, withOomScoreAdj } from "../util/oom-priority.js";
|
|
41
42
|
|
|
42
43
|
const log = getLogger("acp:client-handler");
|
|
43
44
|
|
|
@@ -389,7 +390,11 @@ export class VellumAcpClientHandler implements Client {
|
|
|
389
390
|
}
|
|
390
391
|
}
|
|
391
392
|
|
|
392
|
-
const
|
|
393
|
+
const [command, ...wrappedArgs] = withOomScoreAdj(
|
|
394
|
+
[params.command, ...args],
|
|
395
|
+
CHILD_OOM_SCORE_ADJ,
|
|
396
|
+
);
|
|
397
|
+
const proc = spawn(command, wrappedArgs, {
|
|
393
398
|
cwd: params.cwd ?? undefined,
|
|
394
399
|
stdio: ["ignore", "pipe", "pipe"],
|
|
395
400
|
env,
|
package/src/agent/loop.ts
CHANGED
|
@@ -14,7 +14,10 @@ import {
|
|
|
14
14
|
getCalibrationProviderKey,
|
|
15
15
|
} from "../context/token-estimator.js";
|
|
16
16
|
import { spoolAndStubOversizedToolResults } from "../context/tool-result-spool.js";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
looksLikeContextOverflowError,
|
|
19
|
+
parseActualTokensFromError,
|
|
20
|
+
} from "../daemon/parse-actual-tokens-from-error.js";
|
|
18
21
|
import type { TrustContext } from "../daemon/trust-context-types.js";
|
|
19
22
|
import type {
|
|
20
23
|
AgentLoopExitReason,
|
|
@@ -48,10 +51,7 @@ import type {
|
|
|
48
51
|
ToolDefinition,
|
|
49
52
|
ToolResultContent,
|
|
50
53
|
} from "../providers/types.js";
|
|
51
|
-
import {
|
|
52
|
-
isContextOverflowError,
|
|
53
|
-
NATIVE_WEB_SEARCH_TOOL_NAME,
|
|
54
|
-
} from "../providers/types.js";
|
|
54
|
+
import { NATIVE_WEB_SEARCH_TOOL_NAME } from "../providers/types.js";
|
|
55
55
|
import { recordWatchdogEvent } from "../telemetry/watchdog-events-store.js";
|
|
56
56
|
import {
|
|
57
57
|
ABORT_SETTLE_GRACE_MS,
|
|
@@ -747,6 +747,12 @@ interface AgentLoopRunOptionsBase {
|
|
|
747
747
|
* call-site named profile. Missing profile names silently fall through.
|
|
748
748
|
*/
|
|
749
749
|
overrideProfile?: string;
|
|
750
|
+
/**
|
|
751
|
+
* Who chose `overrideProfile`: `"auto"` when the Auto profile's router
|
|
752
|
+
* picked it for this turn. Threaded onto each send's config so usage
|
|
753
|
+
* attribution reports the routed profile under the `auto` source.
|
|
754
|
+
*/
|
|
755
|
+
overrideProfileOrigin?: "auto";
|
|
750
756
|
/**
|
|
751
757
|
* Float the override profile above the call-site layers (named site
|
|
752
758
|
* profile + call-site override) for non-main-agent call sites — the
|
|
@@ -1454,6 +1460,7 @@ export class AgentLoop {
|
|
|
1454
1460
|
supportsDynamicUi = true,
|
|
1455
1461
|
trust,
|
|
1456
1462
|
overrideProfile,
|
|
1463
|
+
overrideProfileOrigin,
|
|
1457
1464
|
forceOverrideProfile = false,
|
|
1458
1465
|
resolveOverrideProfile,
|
|
1459
1466
|
onModelCallPrepared,
|
|
@@ -2036,6 +2043,16 @@ export class AgentLoop {
|
|
|
2036
2043
|
const effectiveOverrideProfile = resolveEffectiveOverrideProfile();
|
|
2037
2044
|
if (effectiveOverrideProfile) {
|
|
2038
2045
|
providerConfig.overrideProfile = effectiveOverrideProfile;
|
|
2046
|
+
// The origin describes the turn-start override. A profile switched
|
|
2047
|
+
// in mid-turn (a confirmed profile session) is the user's pick, so
|
|
2048
|
+
// the origin applies only while the effective override is still
|
|
2049
|
+
// the one the turn started with.
|
|
2050
|
+
if (
|
|
2051
|
+
overrideProfileOrigin &&
|
|
2052
|
+
effectiveOverrideProfile === overrideProfile
|
|
2053
|
+
) {
|
|
2054
|
+
providerConfig.overrideProfileOrigin = overrideProfileOrigin;
|
|
2055
|
+
}
|
|
2039
2056
|
if (forceOverrideProfile) {
|
|
2040
2057
|
providerConfig.forceOverrideProfile = true;
|
|
2041
2058
|
}
|
|
@@ -2236,7 +2253,13 @@ export class AgentLoop {
|
|
|
2236
2253
|
// resolver layers `llm.profiles[overrideProfile]` at the top of
|
|
2237
2254
|
// precedence for the user-facing call, so a model router can pick
|
|
2238
2255
|
// the profile per message; clearing it drops any seeded override.
|
|
2256
|
+
// The hook context is seeded with the effective override, so an
|
|
2257
|
+
// unchanged profile is still the router's pick and keeps its
|
|
2258
|
+
// origin; a profile the hook changed or cleared is the hook's.
|
|
2239
2259
|
const hookModelProfile = finalPreModelCtx.modelProfile?.trim();
|
|
2260
|
+
if (hookModelProfile !== effectiveOverrideProfile) {
|
|
2261
|
+
delete providerConfig.overrideProfileOrigin;
|
|
2262
|
+
}
|
|
2240
2263
|
if (hookModelProfile) {
|
|
2241
2264
|
providerConfig.overrideProfile = hookModelProfile;
|
|
2242
2265
|
if (forceOverrideProfile) {
|
|
@@ -3170,7 +3193,7 @@ export class AgentLoop {
|
|
|
3170
3193
|
// it is disabled (e.g. agent wakes) there is no ladder to drive, so the
|
|
3171
3194
|
// overflow falls through to the generic error path below.
|
|
3172
3195
|
if (
|
|
3173
|
-
|
|
3196
|
+
looksLikeContextOverflowError(error) &&
|
|
3174
3197
|
(options.resolveContextWindow?.().overflowRecovery.enabled ?? false)
|
|
3175
3198
|
) {
|
|
3176
3199
|
if (overflowLadderExhausted) {
|
|
@@ -19,6 +19,11 @@ export const DocumentEditorShowEventSchema = z.object({
|
|
|
19
19
|
surfaceId: z.string(),
|
|
20
20
|
title: z.string(),
|
|
21
21
|
initialContent: z.string(),
|
|
22
|
+
/**
|
|
23
|
+
* The document's revision once this content is in place. A client that
|
|
24
|
+
* saves with `baseRevision` adopts it as its new base.
|
|
25
|
+
*/
|
|
26
|
+
revision: z.number().optional(),
|
|
22
27
|
});
|
|
23
28
|
|
|
24
29
|
export type DocumentEditorShowEvent = z.infer<
|
|
@@ -20,6 +20,16 @@ export const DocumentEditorUpdateEventSchema = z.object({
|
|
|
20
20
|
surfaceId: z.string(),
|
|
21
21
|
markdown: z.string(),
|
|
22
22
|
mode: z.string(),
|
|
23
|
+
/**
|
|
24
|
+
* The document's revision once this content is in place. A client that
|
|
25
|
+
* saves with `baseRevision` adopts it as its new base.
|
|
26
|
+
*/
|
|
27
|
+
revision: z.number().optional(),
|
|
28
|
+
/**
|
|
29
|
+
* The document's title when this update also sets it (a restore). A client
|
|
30
|
+
* renames the open document to it.
|
|
31
|
+
*/
|
|
32
|
+
title: z.string().optional(),
|
|
23
33
|
});
|
|
24
34
|
|
|
25
35
|
export type DocumentEditorUpdateEvent = z.infer<
|