@vellumai/assistant 0.12.5 → 0.12.6-dev.202609292116.41f7caa
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 +26 -3
- 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__/list-messages-client-message-id.test.ts +43 -0
- 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 +38 -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__/skill-execute-input.test.ts +11 -0
- package/src/__tests__/tool-approval-handler.test.ts +4 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +26 -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-unparseable-tool-retry.test.ts +333 -0
- package/src/agent/loop.ts +161 -17
- 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__/call-controller.test.ts +273 -1
- package/src/calls/__tests__/media-stream-server-integration.test.ts +40 -0
- package/src/calls/__tests__/media-stream-stt-session.test.ts +33 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +54 -0
- package/src/calls/call-constants.ts +10 -0
- package/src/calls/call-controller.ts +359 -25
- package/src/calls/channel-admission-reader.ts +15 -9
- package/src/calls/media-stream-server.ts +18 -0
- package/src/calls/media-stream-stt-session.ts +30 -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 +54 -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 +9 -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-handlers.ts +18 -2
- package/src/daemon/conversation-agent-loop.ts +14 -6
- package/src/daemon/conversation-evictor.ts +50 -16
- package/src/daemon/conversation-messaging.ts +4 -0
- package/src/daemon/conversation-process.ts +15 -0
- package/src/daemon/conversation-queue-manager.ts +2 -0
- package/src/daemon/conversation.ts +2 -0
- 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/handlers/shared.ts +13 -2
- package/src/daemon/host-cu-proxy.ts +34 -3
- package/src/daemon/lifecycle.ts +15 -2
- package/src/daemon/process-message.ts +5 -0
- 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/i18n/__tests__/i18n.test.ts +25 -0
- package/src/i18n/assistant-text.ts +18 -0
- package/src/i18n/index.ts +1 -0
- package/src/i18n/messages.ts +11 -0
- 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/__tests__/unparseable-tool-args.test.ts +25 -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 +33 -2
- 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/unparseable-tool-args.ts +29 -5
- 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-reply-delivery.ts +2 -0
- package/src/runtime/channel-retry-sweep.ts +1 -2
- package/src/runtime/http-types.ts +3 -0
- 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/conversation-routes.ts +7 -0
- 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/inbound-stages/background-dispatch.ts +4 -0
- 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/skills/execute.ts +10 -7
- package/src/tools/terminal/shell.ts +3 -3
- package/src/tools/tool-approval-handler.ts +9 -1
- 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
|
@@ -166,6 +166,7 @@ describe("identity routes — health endpoint", () => {
|
|
|
166
166
|
memoryOptOut: true,
|
|
167
167
|
retryLastTurn: true,
|
|
168
168
|
appPins: true,
|
|
169
|
+
chatsSettings: true,
|
|
169
170
|
});
|
|
170
171
|
|
|
171
172
|
// Profiler should either be absent or show enabled: false
|
|
@@ -492,9 +493,9 @@ describe("identity routes — /readyz readiness gate", () => {
|
|
|
492
493
|
expect(body.ready).toBe(false);
|
|
493
494
|
expect(body.reason).toBe("db_migrations_failed");
|
|
494
495
|
expect((body.dbMigrations as Record<string, unknown>).state).toBe("failed");
|
|
495
|
-
expect(
|
|
496
|
-
|
|
497
|
-
);
|
|
496
|
+
expect(
|
|
497
|
+
(body.dbMigrations as Record<string, unknown>).failedMigrations,
|
|
498
|
+
).toEqual([{ name: "flakyStep", error: "transient failure" }]);
|
|
498
499
|
});
|
|
499
500
|
|
|
500
501
|
test("returns 200 even if CES is down", async () => {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { beforeEach, describe, expect, test } from "bun:test";
|
|
10
10
|
|
|
11
|
+
import { MESSAGE_KEYS } from "../i18n/index.js";
|
|
11
12
|
import { setConfig } from "./helpers/set-config.js";
|
|
12
13
|
|
|
13
14
|
// Keep the memory system off so addMessage skips indexing side effects.
|
|
@@ -31,6 +32,7 @@ function resetTables() {
|
|
|
31
32
|
|
|
32
33
|
interface MessagePayload {
|
|
33
34
|
role: string;
|
|
35
|
+
textSegments?: string[];
|
|
34
36
|
clientMessageId?: string;
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -59,6 +61,47 @@ describe("handleListMessages clientMessageId", () => {
|
|
|
59
61
|
expect(body.messages[0].clientMessageId).toBe("nonce-abc");
|
|
60
62
|
});
|
|
61
63
|
|
|
64
|
+
test("localizes persisted assistant keys without rewriting legacy text", async () => {
|
|
65
|
+
const localizedConv = createConversation();
|
|
66
|
+
await addMessage(
|
|
67
|
+
localizedConv.id,
|
|
68
|
+
"assistant",
|
|
69
|
+
JSON.stringify([
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: MESSAGE_KEYS.AGENT_LOOP_UNPARSEABLE_TOOL_RETRY_STOP,
|
|
73
|
+
},
|
|
74
|
+
]),
|
|
75
|
+
{ skipIndexing: true },
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const localizedResponse = await handleListMessages({
|
|
79
|
+
queryParams: { conversationId: localizedConv.id },
|
|
80
|
+
headers: { "accept-language": "es" },
|
|
81
|
+
});
|
|
82
|
+
const localizedBody = localizedResponse as { messages: MessagePayload[] };
|
|
83
|
+
expect(localizedBody.messages[0]?.textSegments).toEqual([
|
|
84
|
+
"Me detuve después de varias llamadas de herramienta con formato incorrecto para evitar que esta conversación creciera indefinidamente. Inténtalo de nuevo o cambia de modelo si el problema continúa.",
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const legacyConv = createConversation();
|
|
88
|
+
const legacy =
|
|
89
|
+
"I stopped after repeated malformed tool calls to keep this conversation from growing indefinitely. Please try again, or switch models if the problem continues.";
|
|
90
|
+
await addMessage(
|
|
91
|
+
legacyConv.id,
|
|
92
|
+
"assistant",
|
|
93
|
+
JSON.stringify([{ type: "text", text: legacy }]),
|
|
94
|
+
{ skipIndexing: true },
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const legacyResponse = await handleListMessages({
|
|
98
|
+
queryParams: { conversationId: legacyConv.id },
|
|
99
|
+
headers: { "accept-language": "es" },
|
|
100
|
+
});
|
|
101
|
+
const legacyBody = legacyResponse as { messages: MessagePayload[] };
|
|
102
|
+
expect(legacyBody.messages[0]?.textSegments).toEqual([legacy]);
|
|
103
|
+
});
|
|
104
|
+
|
|
62
105
|
test("omits clientMessageId when the row was persisted without one", async () => {
|
|
63
106
|
// GIVEN a user message persisted without a client nonce (e.g. a channel send)
|
|
64
107
|
const conv = createConversation();
|
|
@@ -390,9 +390,9 @@ describe("LLM catalog parity: daemon vs client", () => {
|
|
|
390
390
|
});
|
|
391
391
|
});
|
|
392
392
|
|
|
393
|
-
test("Fireworks catalog includes GLM 5.
|
|
393
|
+
test("Fireworks catalog includes GLM 5.3", () => {
|
|
394
394
|
expect(
|
|
395
|
-
isModelInCatalog("fireworks", "accounts/fireworks/models/glm-
|
|
395
|
+
isModelInCatalog("fireworks", "accounts/fireworks/models/glm-5p3"),
|
|
396
396
|
).toBe(true);
|
|
397
397
|
|
|
398
398
|
const fireworks = PROVIDER_CATALOG.find(
|
|
@@ -400,10 +400,10 @@ describe("LLM catalog parity: daemon vs client", () => {
|
|
|
400
400
|
);
|
|
401
401
|
expect(
|
|
402
402
|
fireworks?.models.find(
|
|
403
|
-
(model) => model.id === "accounts/fireworks/models/glm-
|
|
403
|
+
(model) => model.id === "accounts/fireworks/models/glm-5p3",
|
|
404
404
|
),
|
|
405
405
|
).toMatchObject({
|
|
406
|
-
displayName: "GLM 5.
|
|
406
|
+
displayName: "GLM 5.3",
|
|
407
407
|
contextWindowTokens: 1040000,
|
|
408
408
|
maxOutputTokens: 131072,
|
|
409
409
|
supportsToolUse: true,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { saveRawConfig } from "../config/loader.js";
|
|
4
|
+
|
|
3
5
|
// ── Mock logger ──────────────────────────────────────────────────────────────
|
|
4
6
|
|
|
5
7
|
// ── Mock sleep so retry tests don't slow down the suite ──────────────────────
|
|
6
8
|
|
|
9
|
+
let onRetrySleep: () => Promise<void> = async () => {};
|
|
7
10
|
mock.module("../util/retry.js", () => ({
|
|
8
|
-
sleep: async (_ms: number): Promise<void> =>
|
|
11
|
+
sleep: async (_ms: number): Promise<void> => onRetrySleep(),
|
|
9
12
|
isRetryableStatus: (status: number): boolean =>
|
|
10
13
|
status === 429 || status >= 500,
|
|
11
14
|
isRetryableNetworkError: (error: unknown): boolean => {
|
|
@@ -41,10 +44,12 @@ const fetchResponses: Array<{ ok: boolean; status: number; body?: string }> =
|
|
|
41
44
|
[];
|
|
42
45
|
const fetchErrors: Error[] = [];
|
|
43
46
|
let clientAvailable = true;
|
|
47
|
+
let onClientCreation: () => Promise<void> = async () => {};
|
|
44
48
|
|
|
45
49
|
mock.module("../platform/client.js", () => ({
|
|
46
50
|
VellumPlatformClient: {
|
|
47
51
|
create: async () => {
|
|
52
|
+
await onClientCreation();
|
|
48
53
|
if (!clientAvailable) {
|
|
49
54
|
return null;
|
|
50
55
|
}
|
|
@@ -117,12 +122,89 @@ function makeDestination(
|
|
|
117
122
|
|
|
118
123
|
describe("PlatformPushAdapter", () => {
|
|
119
124
|
beforeEach(() => {
|
|
125
|
+
saveRawConfig({});
|
|
120
126
|
fetchCalls.length = 0;
|
|
121
127
|
fetchResponses.length = 0;
|
|
122
128
|
fetchErrors.length = 0;
|
|
123
129
|
clientAvailable = true;
|
|
130
|
+
onRetrySleep = async () => {};
|
|
131
|
+
onClientCreation = async () => {};
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("skips a disabled chat reply without sending a native push", async () => {
|
|
135
|
+
saveRawConfig({ notifications: { newMessageEnabled: false } });
|
|
136
|
+
const result = await new PlatformPushAdapter().send(
|
|
137
|
+
makePayload({ sourceEventName: "chat.assistant_reply" }),
|
|
138
|
+
makeDestination(),
|
|
139
|
+
);
|
|
140
|
+
expect(result).toMatchObject({
|
|
141
|
+
success: false,
|
|
142
|
+
skipped: true,
|
|
143
|
+
remotePushAccepted: false,
|
|
144
|
+
});
|
|
145
|
+
expect(fetchCalls).toHaveLength(0);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("rechecks the setting after platform client creation", async () => {
|
|
149
|
+
onClientCreation = async () => {
|
|
150
|
+
saveRawConfig({ notifications: { newMessageEnabled: false } });
|
|
151
|
+
};
|
|
152
|
+
const result = await new PlatformPushAdapter().send(
|
|
153
|
+
makePayload({ sourceEventName: "chat.assistant_reply" }),
|
|
154
|
+
makeDestination(),
|
|
155
|
+
);
|
|
156
|
+
expect(result).toMatchObject({
|
|
157
|
+
success: false,
|
|
158
|
+
skipped: true,
|
|
159
|
+
remotePushAccepted: false,
|
|
160
|
+
});
|
|
161
|
+
expect(fetchCalls).toHaveLength(0);
|
|
124
162
|
});
|
|
125
163
|
|
|
164
|
+
test.each([false, true])(
|
|
165
|
+
"stops retries after disabling replies (accepted push: %s)",
|
|
166
|
+
async (accepted) => {
|
|
167
|
+
fetchResponses.push({
|
|
168
|
+
ok: false,
|
|
169
|
+
status: 503,
|
|
170
|
+
body: accepted ? '{"accepted_platforms":["ios"]}' : "{}",
|
|
171
|
+
});
|
|
172
|
+
onRetrySleep = async () => {
|
|
173
|
+
saveRawConfig({ notifications: { newMessageEnabled: false } });
|
|
174
|
+
};
|
|
175
|
+
const result = await new PlatformPushAdapter().send(
|
|
176
|
+
makePayload({ sourceEventName: "chat.assistant_reply" }),
|
|
177
|
+
makeDestination(),
|
|
178
|
+
);
|
|
179
|
+
expect(fetchCalls).toHaveLength(1);
|
|
180
|
+
expect(result).toMatchObject({
|
|
181
|
+
success: accepted,
|
|
182
|
+
skipped: !accepted,
|
|
183
|
+
remotePushAccepted: accepted,
|
|
184
|
+
remotePushPlatforms: accepted ? ["ios"] : undefined,
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
test.each([
|
|
190
|
+
"schedule.result",
|
|
191
|
+
"schedule.notify",
|
|
192
|
+
"guardian.question",
|
|
193
|
+
"activity.failed",
|
|
194
|
+
"chat.assistant_reply.extra",
|
|
195
|
+
])(
|
|
196
|
+
"keeps %s native push enabled when ordinary reply alerts are off",
|
|
197
|
+
async (sourceEventName) => {
|
|
198
|
+
saveRawConfig({ notifications: { newMessageEnabled: false } });
|
|
199
|
+
const result = await new PlatformPushAdapter().send(
|
|
200
|
+
makePayload({ sourceEventName }),
|
|
201
|
+
makeDestination(),
|
|
202
|
+
);
|
|
203
|
+
expect(result.success).toBe(true);
|
|
204
|
+
expect(fetchCalls).toHaveLength(1);
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
126
208
|
test("channel is 'platform'", () => {
|
|
127
209
|
expect(new PlatformPushAdapter().channel).toBe("platform");
|
|
128
210
|
});
|
|
@@ -48,6 +48,8 @@ let mockOAuthCallbackUrl = "";
|
|
|
48
48
|
// getPublicBaseUrl.
|
|
49
49
|
mock.module("../inbound/public-ingress-urls.js", () => ({
|
|
50
50
|
getOAuthCallbackUrl: () => mockOAuthCallbackUrl,
|
|
51
|
+
getMcpOAuthClientMetadataUrl: () =>
|
|
52
|
+
"http://localhost/oauth/client-metadata.json",
|
|
51
53
|
getPublicBaseUrl: (config?: { ingress?: { publicBaseUrl?: string } }) => {
|
|
52
54
|
const url = config?.ingress?.publicBaseUrl ?? "";
|
|
53
55
|
if (!url) {
|
|
@@ -1178,6 +1178,33 @@ describe("OpenAIProvider", () => {
|
|
|
1178
1178
|
});
|
|
1179
1179
|
});
|
|
1180
1180
|
|
|
1181
|
+
test("bounds malformed arguments in the diagnostic raw response only", async () => {
|
|
1182
|
+
const raw = '{"content":"' + "x".repeat(1_000);
|
|
1183
|
+
fakeChunks = [
|
|
1184
|
+
...toolCallChunks([{ id: "call_large_bad", name: "test", args: raw }]),
|
|
1185
|
+
usageChunk(10, 5),
|
|
1186
|
+
];
|
|
1187
|
+
|
|
1188
|
+
const result = await provider.sendMessage([userMsg("test")]);
|
|
1189
|
+
|
|
1190
|
+
expect(result.content[0]).toEqual({
|
|
1191
|
+
type: "tool_use",
|
|
1192
|
+
id: "call_large_bad",
|
|
1193
|
+
name: "test",
|
|
1194
|
+
input: { _raw: raw },
|
|
1195
|
+
});
|
|
1196
|
+
const rawResponse = result.rawResponse as {
|
|
1197
|
+
choices: Array<{
|
|
1198
|
+
message: {
|
|
1199
|
+
tool_calls: Array<{ function: { arguments: string } }>;
|
|
1200
|
+
};
|
|
1201
|
+
}>;
|
|
1202
|
+
};
|
|
1203
|
+
expect(
|
|
1204
|
+
rawResponse.choices[0]!.message.tool_calls[0]!.function.arguments,
|
|
1205
|
+
).toBe(raw.slice(0, 200) + "…");
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1181
1208
|
// -----------------------------------------------------------------------
|
|
1182
1209
|
// stream_options and model
|
|
1183
1210
|
// -----------------------------------------------------------------------
|
|
@@ -1960,10 +1987,10 @@ describe("FireworksProvider reasoning_effort ceiling", () => {
|
|
|
1960
1987
|
lastCreateParams = null;
|
|
1961
1988
|
});
|
|
1962
1989
|
|
|
1963
|
-
test('DeepSeek V4
|
|
1990
|
+
test('DeepSeek V4.1 Flash accepts "max" unclamped', async () => {
|
|
1964
1991
|
const fw = new FireworksProvider(
|
|
1965
1992
|
"fw-key",
|
|
1966
|
-
"accounts/fireworks/models/deepseek-
|
|
1993
|
+
"accounts/fireworks/models/deepseek-v4p1-flash",
|
|
1967
1994
|
);
|
|
1968
1995
|
await fw.sendMessage([userMsg("hi")], {
|
|
1969
1996
|
systemPrompt: "system",
|
|
@@ -1972,10 +1999,10 @@ describe("FireworksProvider reasoning_effort ceiling", () => {
|
|
|
1972
1999
|
expect(lastCreateParams!.reasoning_effort).toBe("max");
|
|
1973
2000
|
});
|
|
1974
2001
|
|
|
1975
|
-
test('DeepSeek V4
|
|
2002
|
+
test('DeepSeek V4.1 Flash accepts "xhigh" unclamped', async () => {
|
|
1976
2003
|
const fw = new FireworksProvider(
|
|
1977
2004
|
"fw-key",
|
|
1978
|
-
"accounts/fireworks/models/deepseek-
|
|
2005
|
+
"accounts/fireworks/models/deepseek-v4p1-flash",
|
|
1979
2006
|
);
|
|
1980
2007
|
await fw.sendMessage([userMsg("hi")], {
|
|
1981
2008
|
systemPrompt: "system",
|
|
@@ -1984,10 +2011,10 @@ describe("FireworksProvider reasoning_effort ceiling", () => {
|
|
|
1984
2011
|
expect(lastCreateParams!.reasoning_effort).toBe("xhigh");
|
|
1985
2012
|
});
|
|
1986
2013
|
|
|
1987
|
-
test('
|
|
2014
|
+
test('MiniMax M3 clamps "xhigh"/"max" down to "high"', async () => {
|
|
1988
2015
|
const fw = new FireworksProvider(
|
|
1989
2016
|
"fw-key",
|
|
1990
|
-
"accounts/fireworks/models/
|
|
2017
|
+
"accounts/fireworks/models/minimax-m3",
|
|
1991
2018
|
);
|
|
1992
2019
|
await fw.sendMessage([userMsg("hi")], {
|
|
1993
2020
|
systemPrompt: "system",
|
|
@@ -2016,7 +2043,7 @@ describe("FireworksProvider reasoning_effort ceiling", () => {
|
|
|
2016
2043
|
test("effort below ceiling is forwarded verbatim", async () => {
|
|
2017
2044
|
const fw = new FireworksProvider(
|
|
2018
2045
|
"fw-key",
|
|
2019
|
-
"accounts/fireworks/models/deepseek-
|
|
2046
|
+
"accounts/fireworks/models/deepseek-v4p1-flash",
|
|
2020
2047
|
);
|
|
2021
2048
|
await fw.sendMessage([userMsg("hi")], {
|
|
2022
2049
|
systemPrompt: "system",
|
|
@@ -2028,7 +2055,7 @@ describe("FireworksProvider reasoning_effort ceiling", () => {
|
|
|
2028
2055
|
test('effort: "none" passes through regardless of ceiling', async () => {
|
|
2029
2056
|
const fw = new FireworksProvider(
|
|
2030
2057
|
"fw-key",
|
|
2031
|
-
"accounts/fireworks/models/
|
|
2058
|
+
"accounts/fireworks/models/minimax-m3",
|
|
2032
2059
|
);
|
|
2033
2060
|
await fw.sendMessage([userMsg("hi")], {
|
|
2034
2061
|
systemPrompt: "system",
|
|
@@ -2040,13 +2067,13 @@ describe("FireworksProvider reasoning_effort ceiling", () => {
|
|
|
2040
2067
|
test("model override picks ceiling from runtime model, not constructor model", async () => {
|
|
2041
2068
|
const fw = new FireworksProvider(
|
|
2042
2069
|
"fw-key",
|
|
2043
|
-
"accounts/fireworks/models/
|
|
2070
|
+
"accounts/fireworks/models/minimax-m3",
|
|
2044
2071
|
);
|
|
2045
2072
|
await fw.sendMessage([userMsg("hi")], {
|
|
2046
2073
|
systemPrompt: "system",
|
|
2047
2074
|
config: {
|
|
2048
2075
|
effort: "max",
|
|
2049
|
-
model: "accounts/fireworks/models/deepseek-
|
|
2076
|
+
model: "accounts/fireworks/models/deepseek-v4p1-flash",
|
|
2050
2077
|
},
|
|
2051
2078
|
});
|
|
2052
2079
|
expect(lastCreateParams!.reasoning_effort).toBe("max");
|
|
@@ -2111,7 +2138,7 @@ describe("FireworksProvider sparse reasoning_effort support (GLM 5.3)", () => {
|
|
|
2111
2138
|
|
|
2112
2139
|
test("models without supportedEfforts are unaffected", async () => {
|
|
2113
2140
|
expect(
|
|
2114
|
-
await send("accounts/fireworks/models/deepseek-
|
|
2141
|
+
await send("accounts/fireworks/models/deepseek-v4p1-flash", "medium"),
|
|
2115
2142
|
).toBe("medium");
|
|
2116
2143
|
});
|
|
2117
2144
|
});
|
|
@@ -10,6 +10,17 @@ import {
|
|
|
10
10
|
} from "../util/pricing.js";
|
|
11
11
|
|
|
12
12
|
describe("resolvePricing", () => {
|
|
13
|
+
test.each([
|
|
14
|
+
["accounts/fireworks/models/glm-5p2", 1.4 + 4.4],
|
|
15
|
+
["accounts/fireworks/models/kimi-k2p6", 0.95 + 4.0],
|
|
16
|
+
["accounts/fireworks/models/deepseek-v4-pro-0813", 1.32 + 3.96],
|
|
17
|
+
["accounts/fireworks/models/deepseek-v4-flash-0731", 0.14 + 0.28],
|
|
18
|
+
])("prices stored usage for retired Fireworks model %s", (model, cost) => {
|
|
19
|
+
const result = resolvePricing("fireworks", model, 1_000_000, 1_000_000);
|
|
20
|
+
expect(result.pricingStatus).toBe("priced");
|
|
21
|
+
expect(result.estimatedCostUsd).toBeCloseTo(cost, 10);
|
|
22
|
+
});
|
|
23
|
+
|
|
13
24
|
describe("Anthropic models", () => {
|
|
14
25
|
test("returns priced for claude-opus-4-6", () => {
|
|
15
26
|
const result = resolvePricing(
|
|
@@ -6,6 +6,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
6
6
|
import { setIngressPublicBaseUrl } from "../config/env.js";
|
|
7
7
|
import { IngressConfigSchema } from "../config/schemas/ingress.js";
|
|
8
8
|
import {
|
|
9
|
+
getMcpOAuthClientMetadataUrl,
|
|
9
10
|
getOAuthCallbackUrl,
|
|
10
11
|
getPublicBaseUrl,
|
|
11
12
|
getTelegramWebhookUrl,
|
|
@@ -307,6 +308,31 @@ describe("getOAuthCallbackUrl", () => {
|
|
|
307
308
|
});
|
|
308
309
|
expect(url).toBe("https://example.com/webhooks/oauth/callback");
|
|
309
310
|
});
|
|
311
|
+
|
|
312
|
+
test("canonicalizes the base before building OAuth URLs", () => {
|
|
313
|
+
const config = {
|
|
314
|
+
ingress: {
|
|
315
|
+
publicBaseUrl: "https://EXAMPLE.com:443/a/../assistant-123///",
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
expect(getOAuthCallbackUrl(config)).toBe(
|
|
320
|
+
"https://example.com/assistant-123/webhooks/oauth/callback",
|
|
321
|
+
);
|
|
322
|
+
expect(getMcpOAuthClientMetadataUrl(config)).toBe(
|
|
323
|
+
"https://example.com/assistant-123/oauth/client-metadata.json",
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
describe("getMcpOAuthClientMetadataUrl", () => {
|
|
329
|
+
test("builds the public metadata URL", () => {
|
|
330
|
+
expect(
|
|
331
|
+
getMcpOAuthClientMetadataUrl({
|
|
332
|
+
ingress: { publicBaseUrl: "https://example.com/assistant-123/" },
|
|
333
|
+
}),
|
|
334
|
+
).toBe("https://example.com/assistant-123/oauth/client-metadata.json");
|
|
335
|
+
});
|
|
310
336
|
});
|
|
311
337
|
|
|
312
338
|
// ---------------------------------------------------------------------------
|
|
@@ -144,6 +144,53 @@ describe("retry normalization: thinking + forced tool_choice", () => {
|
|
|
144
144
|
expect(lastConfig()?.thinking).toEqual({ type: "adaptive" });
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
+
for (const [providerName, model] of [
|
|
148
|
+
["anthropic", "claude-sonnet-5-5"],
|
|
149
|
+
["anthropic", "claude-opus-5-5"],
|
|
150
|
+
["openrouter", "anthropic/claude-sonnet-5.5"],
|
|
151
|
+
["vercel-ai-gateway", "anthropic/claude-sonnet-5.5"],
|
|
152
|
+
] as const) {
|
|
153
|
+
test(`downgrades forced tool_choice to auto for ${providerName} ${model}`, async () => {
|
|
154
|
+
// These models always reason and reject forced tool use, so stripping
|
|
155
|
+
// `thinking` is not enough: the forced choice itself has to go.
|
|
156
|
+
setLlmConfig({
|
|
157
|
+
callSites: {
|
|
158
|
+
memoryExtraction: { provider: providerName, model },
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
const { provider, lastConfig } = makePipeline(providerName);
|
|
162
|
+
await provider.sendMessage([userMessage], {
|
|
163
|
+
config: {
|
|
164
|
+
callSite: "memoryExtraction",
|
|
165
|
+
tool_choice: { type: "tool", name: "extract_graph_diff" },
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
expect(lastConfig()?.tool_choice).toEqual({ type: "auto" });
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
test("keeps forced tool_choice for an adaptive-only model off the Anthropic wire", async () => {
|
|
173
|
+
setLlmConfig({
|
|
174
|
+
callSites: {
|
|
175
|
+
memoryExtraction: {
|
|
176
|
+
provider: "fireworks",
|
|
177
|
+
model: "accounts/fireworks/models/glm-5p3",
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
const { provider, lastConfig } = makePipeline("fireworks");
|
|
182
|
+
await provider.sendMessage([userMessage], {
|
|
183
|
+
config: {
|
|
184
|
+
callSite: "memoryExtraction",
|
|
185
|
+
tool_choice: { type: "tool", name: "extract_graph_diff" },
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
expect(lastConfig()?.tool_choice).toEqual({
|
|
189
|
+
type: "tool",
|
|
190
|
+
name: "extract_graph_diff",
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
147
194
|
test("preserves explicit thinking: disabled with forced tool_choice", async () => {
|
|
148
195
|
// Callers like the retriever explicitly set thinking: { type: "disabled" }
|
|
149
196
|
// alongside forced tool_choice. This should pass through unchanged since
|
|
@@ -188,6 +188,17 @@ describe("recoverSkillExecuteEnvelope", () => {
|
|
|
188
188
|
expect(recoverSkillExecuteEnvelope(wrapped)).toBe(wrapped);
|
|
189
189
|
});
|
|
190
190
|
|
|
191
|
+
test("keeps recovered JSON wrapped when it lacks a string tool name", () => {
|
|
192
|
+
for (const raw of [
|
|
193
|
+
JSON.stringify({ input: { content: "hi" }, activity: "x" }),
|
|
194
|
+
JSON.stringify({ tool: 42, input: {}, activity: "x" }),
|
|
195
|
+
JSON.stringify(["document_update"]),
|
|
196
|
+
]) {
|
|
197
|
+
const wrapped = { _raw: raw };
|
|
198
|
+
expect(recoverSkillExecuteEnvelope(wrapped)).toBe(wrapped);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
191
202
|
test("passes a normal envelope through untouched", () => {
|
|
192
203
|
const envelope = {
|
|
193
204
|
tool: "document_update",
|
|
@@ -1357,6 +1357,10 @@ describe("ToolApprovalHandler / unparseable tool args gate", () => {
|
|
|
1357
1357
|
}
|
|
1358
1358
|
expect(result.result.content).not.toContain(raw);
|
|
1359
1359
|
expect(result.result.content).toContain("…");
|
|
1360
|
+
expect(auditCalls.error).toHaveLength(1);
|
|
1361
|
+
expect(auditCalls.error[0].input).toEqual({
|
|
1362
|
+
_raw: raw.slice(0, 200) + "…",
|
|
1363
|
+
});
|
|
1360
1364
|
});
|
|
1361
1365
|
|
|
1362
1366
|
test("legitimate input containing a _raw field among others is not rejected", async () => {
|
|
@@ -341,6 +341,32 @@ describe("tool preview lifecycle", () => {
|
|
|
341
341
|
expect((emitted as any).conversationId).toBe("test-session-id");
|
|
342
342
|
});
|
|
343
343
|
|
|
344
|
+
test("caps cumulative app preview payloads and stops forwarding growth", () => {
|
|
345
|
+
const collector = createEventCollector();
|
|
346
|
+
const deps = createMockDeps({ onEvent: collector.onEvent });
|
|
347
|
+
const accumulatedJson = '{"code":"' + "x".repeat(300_000);
|
|
348
|
+
|
|
349
|
+
handleInputJsonDelta(state, deps, {
|
|
350
|
+
type: "input_json_delta",
|
|
351
|
+
toolName: "app_create",
|
|
352
|
+
toolUseId: "toolu_large_app",
|
|
353
|
+
accumulatedJson,
|
|
354
|
+
});
|
|
355
|
+
handleInputJsonDelta(state, deps, {
|
|
356
|
+
type: "input_json_delta",
|
|
357
|
+
toolName: "app_create",
|
|
358
|
+
toolUseId: "toolu_large_app",
|
|
359
|
+
accumulatedJson: accumulatedJson + "more",
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
expect(collector.events).toHaveLength(1);
|
|
363
|
+
const emitted = collector.events[0] as Extract<
|
|
364
|
+
AssistantEvent,
|
|
365
|
+
{ type: "tool_input_delta" }
|
|
366
|
+
>;
|
|
367
|
+
expect(emitted.content).toBe(accumulatedJson.slice(0, 256_000));
|
|
368
|
+
});
|
|
369
|
+
|
|
344
370
|
test("a streaming ui_show visual announces its surface exactly once", () => {
|
|
345
371
|
const collector = createEventCollector();
|
|
346
372
|
const deps = createMockDeps({ onEvent: collector.onEvent });
|
|
@@ -109,6 +109,37 @@ describe("resolveUsageAttribution", () => {
|
|
|
109
109
|
expectResolvedProviderModelMatchesResolver("mainAgent", "pinned");
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
+
test("reports an override the Auto router chose as the auto source", () => {
|
|
113
|
+
setLlmConfig({
|
|
114
|
+
profiles: {
|
|
115
|
+
active: { provider: "openai", model: "gpt-5.4" },
|
|
116
|
+
routed: { provider: "gemini", model: "gemini-3-pro" },
|
|
117
|
+
},
|
|
118
|
+
activeProfile: "active",
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const snapshot = resolveUsageAttribution({
|
|
122
|
+
callSite: "mainAgent",
|
|
123
|
+
overrideProfile: "routed",
|
|
124
|
+
overrideProfileOrigin: "auto",
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(snapshot).toMatchObject({
|
|
128
|
+
appliedProfile: "routed",
|
|
129
|
+
profileSource: "auto",
|
|
130
|
+
resolvedProvider: "gemini",
|
|
131
|
+
resolvedModel: "gemini-3-pro",
|
|
132
|
+
});
|
|
133
|
+
// The origin only relabels an override that actually won.
|
|
134
|
+
expect(
|
|
135
|
+
resolveUsageAttribution({
|
|
136
|
+
callSite: "mainAgent",
|
|
137
|
+
overrideProfile: "missing",
|
|
138
|
+
overrideProfileOrigin: "auto",
|
|
139
|
+
}).profileSource,
|
|
140
|
+
).toBe("active");
|
|
141
|
+
});
|
|
142
|
+
|
|
112
143
|
test("resolves call-site profile attribution", () => {
|
|
113
144
|
setLlmConfig({
|
|
114
145
|
profiles: {
|
|
@@ -100,7 +100,7 @@ describe("133-collapse-provider-connections migration", () => {
|
|
|
100
100
|
source: "user",
|
|
101
101
|
provider: "fireworks",
|
|
102
102
|
provider_connection: "vellum",
|
|
103
|
-
model: "accounts/fireworks/models/
|
|
103
|
+
model: "accounts/fireworks/models/minimax-m3",
|
|
104
104
|
},
|
|
105
105
|
},
|
|
106
106
|
},
|
|
@@ -257,7 +257,7 @@ describe("133-collapse-provider-connections migration", () => {
|
|
|
257
257
|
encoded: {
|
|
258
258
|
source: "user",
|
|
259
259
|
provider: "vellum",
|
|
260
|
-
model: "fireworks/accounts/fireworks/models/
|
|
260
|
+
model: "fireworks/accounts/fireworks/models/minimax-m3",
|
|
261
261
|
},
|
|
262
262
|
},
|
|
263
263
|
},
|
|
@@ -272,7 +272,7 @@ describe("133-collapse-provider-connections migration", () => {
|
|
|
272
272
|
expect(llm.profiles.encoded).toEqual({
|
|
273
273
|
source: "user",
|
|
274
274
|
provider: "vellum",
|
|
275
|
-
model: "accounts/fireworks/models/
|
|
275
|
+
model: "accounts/fireworks/models/minimax-m3",
|
|
276
276
|
});
|
|
277
277
|
});
|
|
278
278
|
|