@vellumai/assistant 0.12.1-staging.1 → 0.12.1
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/AGENTS.md +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/openapi.yaml +1 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +1 -2
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +0 -93
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -8
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +21 -75
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +0 -2
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +21 -8
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -117
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -144
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -39,7 +39,6 @@ import type {
|
|
|
39
39
|
SendMessageOptions,
|
|
40
40
|
} from "@vellumai/plugin-api";
|
|
41
41
|
|
|
42
|
-
import { OpenRouterProvider } from "../../../../../providers/openrouter/client.js";
|
|
43
42
|
import { ProviderError } from "../../../../../util/errors.js";
|
|
44
43
|
import { sectionHeadLine } from "../sections.js";
|
|
45
44
|
import type { MemoryRoutingTurn, Section } from "../types.js";
|
|
@@ -844,91 +843,3 @@ describe("selectPool: sections and keyword-in-context snippets", () => {
|
|
|
844
843
|
);
|
|
845
844
|
});
|
|
846
845
|
});
|
|
847
|
-
|
|
848
|
-
// ---------------------------------------------------------------------------
|
|
849
|
-
// selectPool: cataloged thinking and forced-tool compatibility.
|
|
850
|
-
// ---------------------------------------------------------------------------
|
|
851
|
-
|
|
852
|
-
describe("selectPool: cataloged thinking and forced-tool compatibility", () => {
|
|
853
|
-
test("OpenRouter Kimi K2.6 omits the forced choice and yields a structured selection", async () => {
|
|
854
|
-
// A real OpenAI chat-completions provider stands in for the cataloged
|
|
855
|
-
// OpenRouter Kimi profile. The request succeeds without a reactive retry
|
|
856
|
-
// because the forced select_pages choice is omitted before dispatch.
|
|
857
|
-
const wireRequests: unknown[] = [];
|
|
858
|
-
const kimi = new OpenRouterProvider(
|
|
859
|
-
"test-key",
|
|
860
|
-
"moonshotai/kimi-k2.6-20260420",
|
|
861
|
-
);
|
|
862
|
-
(kimi as unknown as { client: unknown }).client = {
|
|
863
|
-
chat: {
|
|
864
|
-
completions: {
|
|
865
|
-
create: async (params: unknown) => {
|
|
866
|
-
wireRequests.push(JSON.parse(JSON.stringify(params)));
|
|
867
|
-
return {
|
|
868
|
-
async *[Symbol.asyncIterator]() {
|
|
869
|
-
yield {
|
|
870
|
-
choices: [
|
|
871
|
-
{
|
|
872
|
-
delta: {
|
|
873
|
-
tool_calls: [
|
|
874
|
-
{
|
|
875
|
-
index: 0,
|
|
876
|
-
id: "call-1",
|
|
877
|
-
function: {
|
|
878
|
-
name: "select_pages",
|
|
879
|
-
arguments: '{"ids":[3]}',
|
|
880
|
-
},
|
|
881
|
-
},
|
|
882
|
-
],
|
|
883
|
-
},
|
|
884
|
-
finish_reason: "tool_calls",
|
|
885
|
-
},
|
|
886
|
-
],
|
|
887
|
-
usage: { prompt_tokens: 10, completion_tokens: 2 },
|
|
888
|
-
};
|
|
889
|
-
},
|
|
890
|
-
};
|
|
891
|
-
},
|
|
892
|
-
},
|
|
893
|
-
},
|
|
894
|
-
};
|
|
895
|
-
|
|
896
|
-
// The profile layer injects the thinking effort onto the call config in
|
|
897
|
-
// production; emulate that here so the forced tool_choice rides alongside
|
|
898
|
-
// reasoning on the wire.
|
|
899
|
-
providerStub = {
|
|
900
|
-
name: "kimi-openai-compat",
|
|
901
|
-
sendMessage: (messages: Message[], options?: SendMessageOptions) =>
|
|
902
|
-
kimi.sendMessage(messages, {
|
|
903
|
-
...options,
|
|
904
|
-
config: {
|
|
905
|
-
...options?.config,
|
|
906
|
-
effort: "high",
|
|
907
|
-
thinking: { enabled: true },
|
|
908
|
-
},
|
|
909
|
-
}),
|
|
910
|
-
};
|
|
911
|
-
|
|
912
|
-
const selection = await selectPool(makePool(), makeTurn("rollout?"));
|
|
913
|
-
|
|
914
|
-
// The preflight path avoids an incompatible first request, and the
|
|
915
|
-
// pool-level re-prompt loop never engages.
|
|
916
|
-
expect(wireRequests).toHaveLength(1);
|
|
917
|
-
const first = wireRequests[0] as {
|
|
918
|
-
tool_choice?: unknown;
|
|
919
|
-
reasoning?: { effort?: string; summary?: string };
|
|
920
|
-
};
|
|
921
|
-
expect(first.tool_choice).toBeUndefined();
|
|
922
|
-
expect(first.reasoning).toMatchObject({
|
|
923
|
-
effort: "high",
|
|
924
|
-
summary: "detailed",
|
|
925
|
-
});
|
|
926
|
-
expect(
|
|
927
|
-
warnPayloads().filter((p) => p.reason === "provider_error"),
|
|
928
|
-
).toEqual([]);
|
|
929
|
-
|
|
930
|
-
// Structured selection survived: ids [3] is the topic-x finder line.
|
|
931
|
-
expect(selection.keptAll).toBe(false);
|
|
932
|
-
expect(selection.pages).toEqual([{ slug: "topic-x", sections: [] }]);
|
|
933
|
-
});
|
|
934
|
-
});
|
|
@@ -16,10 +16,6 @@ import { getConfig } from "../../../config/loader.js";
|
|
|
16
16
|
import { isMemoryEnabled } from "../../../config/memory-v3-gate.js";
|
|
17
17
|
import { rehydratePlatformCredentials } from "../../../config/platform-rehydration.js";
|
|
18
18
|
import { startConversationEvictor } from "../../../daemon/conversation-evictor.js";
|
|
19
|
-
import {
|
|
20
|
-
startWorkspaceSkillMdMtimePoll,
|
|
21
|
-
stopWorkspaceSkillMdMtimePoll,
|
|
22
|
-
} from "../../../daemon/skill-memory-refresh.js";
|
|
23
19
|
import { resetDb } from "../../../persistence/db-connection.js";
|
|
24
20
|
import {
|
|
25
21
|
EMBEDDING_SHUTDOWN_BUDGET_MS,
|
|
@@ -112,7 +108,6 @@ async function main(): Promise<void> {
|
|
|
112
108
|
shuttingDown = true;
|
|
113
109
|
log.info({ signal }, "Memory worker process shutting down");
|
|
114
110
|
worker?.stop();
|
|
115
|
-
stopWorkspaceSkillMdMtimePoll();
|
|
116
111
|
if (keepAlive != null) {
|
|
117
112
|
clearInterval(keepAlive);
|
|
118
113
|
}
|
|
@@ -166,7 +161,6 @@ async function main(): Promise<void> {
|
|
|
166
161
|
}
|
|
167
162
|
|
|
168
163
|
worker = startMemoryJobsWorkerLoop();
|
|
169
|
-
startWorkspaceSkillMdMtimePoll();
|
|
170
164
|
|
|
171
165
|
// Keep-alive: the worker's setTimeout timers are unref'd, so without
|
|
172
166
|
// this interval the process would exit immediately.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* This module reads those files and projects each entry onto the
|
|
15
15
|
* assistant's own `McpServerConfig` shape, so a plugin-declared server can
|
|
16
16
|
* flow through the same surfaces as one configured in the workspace
|
|
17
|
-
* `
|
|
17
|
+
* `config.json`.
|
|
18
18
|
*
|
|
19
19
|
* Failure isolation follows the spec: an invalid top-level `mcp.json`
|
|
20
20
|
* disables MCP for that plugin only, and an invalid individual server
|
|
@@ -39,17 +39,17 @@
|
|
|
39
39
|
import { existsSync, readFileSync } from "node:fs";
|
|
40
40
|
import { join } from "node:path";
|
|
41
41
|
|
|
42
|
+
import { z } from "zod";
|
|
43
|
+
|
|
42
44
|
import {
|
|
43
45
|
type AllPluginInfo,
|
|
44
46
|
listAllPlugins,
|
|
45
47
|
type ListInstalledPluginsOptions,
|
|
46
48
|
} from "../cli/lib/list-installed-plugins.js";
|
|
47
|
-
import type {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
SpecMcpServerSchema,
|
|
52
|
-
} from "../mcp/spec-schema.js";
|
|
49
|
+
import type {
|
|
50
|
+
McpTransport,
|
|
51
|
+
ResolvedMcpServerConfig,
|
|
52
|
+
} from "../config/schemas/mcp.js";
|
|
53
53
|
import { getLogger } from "../util/logger.js";
|
|
54
54
|
|
|
55
55
|
const log = getLogger("plugin-mcp-servers");
|
|
@@ -77,6 +77,45 @@ export const PLUGIN_MCP_MANIFEST = "mcp.json";
|
|
|
77
77
|
* origin risk.
|
|
78
78
|
*/
|
|
79
79
|
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Wire schema (Agent Plugins 1.0.0)
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
const PluginStdioServerSchema = z.object({
|
|
85
|
+
type: z.literal("stdio"),
|
|
86
|
+
command: z.string().min(1),
|
|
87
|
+
args: z.array(z.string()).optional(),
|
|
88
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
89
|
+
cwd: z.string().optional(),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Remote MCP entry. Agent Plugins 1.0.0 requires `type` and names no
|
|
94
|
+
* default. MCP's current remote transport is Streamable HTTP, so this
|
|
95
|
+
* host fills omitted `type` and the Claude-style `http` alias as
|
|
96
|
+
* `streamable-http`. `sse` stays explicit.
|
|
97
|
+
*/
|
|
98
|
+
const PluginHttpServerSchema = z.object({
|
|
99
|
+
type: z
|
|
100
|
+
.union([
|
|
101
|
+
z.literal("streamable-http"),
|
|
102
|
+
z.literal("sse"),
|
|
103
|
+
z.literal("http").transform(() => "streamable-http" as const),
|
|
104
|
+
])
|
|
105
|
+
.default("streamable-http"),
|
|
106
|
+
url: z.string().min(1),
|
|
107
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const PluginMcpServerSchema = z.union([
|
|
111
|
+
PluginStdioServerSchema,
|
|
112
|
+
PluginHttpServerSchema,
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
const PluginMcpManifestSchema = z.object({
|
|
116
|
+
mcpServers: z.record(z.string(), z.unknown()),
|
|
117
|
+
});
|
|
118
|
+
|
|
80
119
|
// ---------------------------------------------------------------------------
|
|
81
120
|
// Public shape
|
|
82
121
|
// ---------------------------------------------------------------------------
|
|
@@ -212,7 +251,7 @@ export function readPluginMcpServers(
|
|
|
212
251
|
continue;
|
|
213
252
|
}
|
|
214
253
|
|
|
215
|
-
const entry =
|
|
254
|
+
const entry = PluginMcpServerSchema.safeParse(raw);
|
|
216
255
|
if (!entry.success) {
|
|
217
256
|
issues.push({
|
|
218
257
|
pluginName: plugin.name,
|
|
@@ -286,7 +325,7 @@ function parseManifest(
|
|
|
286
325
|
};
|
|
287
326
|
}
|
|
288
327
|
|
|
289
|
-
const manifest =
|
|
328
|
+
const manifest = PluginMcpManifestSchema.safeParse(json);
|
|
290
329
|
if (!manifest.success) {
|
|
291
330
|
return {
|
|
292
331
|
error: `${PLUGIN_MCP_MANIFEST} is missing a valid "mcpServers" object`,
|
|
@@ -295,12 +334,33 @@ function parseManifest(
|
|
|
295
334
|
return { mcpServers: manifest.data.mcpServers };
|
|
296
335
|
}
|
|
297
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Project one spec-shaped entry onto the assistant's transport union. The
|
|
339
|
+
* two vocabularies already agree on type names and required fields, so this
|
|
340
|
+
* is a field copy plus path interpolation for the stdio case.
|
|
341
|
+
*/
|
|
298
342
|
function projectTransport(
|
|
299
|
-
entry:
|
|
343
|
+
entry: z.infer<typeof PluginMcpServerSchema>,
|
|
300
344
|
pluginRoot: string,
|
|
301
|
-
) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
345
|
+
): McpTransport {
|
|
346
|
+
if (entry.type === "stdio") {
|
|
347
|
+
const pluginData = join(pluginRoot, "data");
|
|
348
|
+
const expand = (v: string): string =>
|
|
349
|
+
interpolatePluginPaths(v, pluginRoot, pluginData);
|
|
350
|
+
return {
|
|
351
|
+
type: "stdio",
|
|
352
|
+
command: entry.command,
|
|
353
|
+
args: (entry.args ?? []).map(expand),
|
|
354
|
+
...(entry.env && {
|
|
355
|
+
env: Object.fromEntries(
|
|
356
|
+
Object.entries(entry.env).map(([k, v]) => [k, expand(v)]),
|
|
357
|
+
),
|
|
358
|
+
}),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
type: entry.type,
|
|
363
|
+
url: entry.url,
|
|
364
|
+
...(entry.headers && { headers: entry.headers }),
|
|
365
|
+
};
|
|
306
366
|
}
|
|
@@ -50,8 +50,6 @@ describe("isConnectionCompatibleWithModel", () => {
|
|
|
50
50
|
expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-nano")).toBe(false);
|
|
51
51
|
expect(isConnectionCompatibleWithModel(conn, "gpt-5.5-pro")).toBe(false);
|
|
52
52
|
expect(isConnectionCompatibleWithModel(conn, "gpt-5.3-codex")).toBe(false);
|
|
53
|
-
expect(isConnectionCompatibleWithModel(conn, "gpt-5.4")).toBe(false);
|
|
54
|
-
expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-mini")).toBe(false);
|
|
55
53
|
});
|
|
56
54
|
|
|
57
55
|
test("oauth_subscription connection is compatible with a Codex model", () => {
|
|
@@ -61,6 +59,8 @@ describe("isConnectionCompatibleWithModel", () => {
|
|
|
61
59
|
expect(isConnectionCompatibleWithModel(conn, "gpt-5.6-terra")).toBe(true);
|
|
62
60
|
expect(isConnectionCompatibleWithModel(conn, "gpt-5.6-luna")).toBe(true);
|
|
63
61
|
expect(isConnectionCompatibleWithModel(conn, "gpt-5.5")).toBe(true);
|
|
62
|
+
expect(isConnectionCompatibleWithModel(conn, "gpt-5.4")).toBe(true);
|
|
63
|
+
expect(isConnectionCompatibleWithModel(conn, "gpt-5.4-mini")).toBe(true);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
test("undefined model applies no gating (compatible)", () => {
|
|
@@ -165,7 +165,7 @@ describe("auto-resolution skips oauth_subscription connections for non-Codex mod
|
|
|
165
165
|
|
|
166
166
|
test("Codex model can select the oauth_subscription connection", async () => {
|
|
167
167
|
registerConnections([OPENAI_CODEX, OPENAI_KEY]);
|
|
168
|
-
setOpenAiProfile("gpt-5.
|
|
168
|
+
setOpenAiProfile("gpt-5.4");
|
|
169
169
|
|
|
170
170
|
const result = await getConfiguredProvider("mainAgent", {
|
|
171
171
|
overrideProfile: "openai-any",
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
keepFileAsWorkspaceRef,
|
|
16
16
|
} from "../content-block-size.js";
|
|
17
17
|
import { fileBlockToProviderText } from "../file-block-text.js";
|
|
18
|
-
import { unsignedThoughtSignatureFallback } from "../gemini-thought-signature.js";
|
|
19
18
|
import { base64Source, resolveMediaReferences } from "../media-resolve.js";
|
|
20
19
|
import { PROVIDER_CATALOG } from "../model-catalog.js";
|
|
21
20
|
import { recordProviderRequestDiagnostics } from "../request-diagnostics.js";
|
|
@@ -46,6 +45,13 @@ import {
|
|
|
46
45
|
const GEMINI_CONTEXT_OVERFLOW_TOKEN_PATTERNS =
|
|
47
46
|
/token.?count.*exceeds|exceeds.*maximum.*tokens|prompt.?is.?too.?long|too.?many.?(?:input.?)?tokens|input.?too.?long|context.?length.?exceeded/i;
|
|
48
47
|
|
|
48
|
+
const GEMINI_3_UNSIGNED_TOOL_CALL_THOUGHT_SIGNATURE =
|
|
49
|
+
"context_engineering_is_the_way_to_go";
|
|
50
|
+
|
|
51
|
+
function isGemini3Model(model: string): boolean {
|
|
52
|
+
return model.startsWith("gemini-3") || model.startsWith("models/gemini-3");
|
|
53
|
+
}
|
|
54
|
+
|
|
49
55
|
const THINKING_LEVEL_BY_NAME: Record<ThinkingLevelName, ThinkingLevel> = {
|
|
50
56
|
minimal: ThinkingLevel.MINIMAL,
|
|
51
57
|
low: ThinkingLevel.LOW,
|
|
@@ -429,8 +435,7 @@ export class GeminiProvider implements Provider {
|
|
|
429
435
|
const maxTokens = configObj?.max_tokens as number | undefined;
|
|
430
436
|
const modelOverride = configObj?.model as string | undefined;
|
|
431
437
|
const usageAttributionHeaders = configObj?.usageAttributionHeaders as
|
|
432
|
-
|
|
433
|
-
| undefined;
|
|
438
|
+
Record<string, string> | undefined;
|
|
434
439
|
const activeModel = modelOverride ?? this.model;
|
|
435
440
|
const thinkingConfig = geminiModelSupportsThinking(activeModel)
|
|
436
441
|
? buildThinkingConfig(
|
|
@@ -897,19 +902,28 @@ export class GeminiProvider implements Provider {
|
|
|
897
902
|
parts: genai.Part[],
|
|
898
903
|
model: string,
|
|
899
904
|
): void {
|
|
905
|
+
if (!isGemini3Model(model)) {
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
900
909
|
const functionCallParts = parts.filter((part) => part.functionCall);
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
910
|
+
if (functionCallParts.length === 0) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const hasRealThoughtSignature = functionCallParts.some((part) =>
|
|
915
|
+
Boolean(part.thoughtSignature),
|
|
904
916
|
);
|
|
905
|
-
if (
|
|
917
|
+
if (hasRealThoughtSignature) {
|
|
906
918
|
return;
|
|
907
919
|
}
|
|
908
|
-
|
|
920
|
+
|
|
921
|
+
const firstFunctionCallPart = functionCallParts[0];
|
|
909
922
|
if (!firstFunctionCallPart) {
|
|
910
923
|
return;
|
|
911
924
|
}
|
|
912
|
-
firstFunctionCallPart.thoughtSignature =
|
|
925
|
+
firstFunctionCallPart.thoughtSignature =
|
|
926
|
+
GEMINI_3_UNSIGNED_TOOL_CALL_THOUGHT_SIGNATURE;
|
|
913
927
|
}
|
|
914
928
|
|
|
915
929
|
private supportsGeminiInlineFile(mimeType: string): boolean {
|
|
@@ -76,13 +76,6 @@ export interface CatalogModel {
|
|
|
76
76
|
supportsAudioInput?: boolean;
|
|
77
77
|
supportsToolUse?: boolean;
|
|
78
78
|
supportsEffort?: boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Whether this provider/model serving surface accepts a forced OpenAI
|
|
81
|
-
* chat-completions tool choice while thinking is enabled. Omit unless the
|
|
82
|
-
* combination is known incompatible. Daemon-only: not projected into the
|
|
83
|
-
* client catalog (see scripts/sync-llm-catalog.ts).
|
|
84
|
-
*/
|
|
85
|
-
supportsForcedToolChoiceWithThinking?: boolean;
|
|
86
79
|
pricing?: CatalogModelPricing;
|
|
87
80
|
/**
|
|
88
81
|
* Upper bound for `reasoning_effort` accepted by this model's upstream API.
|
|
@@ -863,9 +856,6 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
863
856
|
cacheReadPer1mTokens: 0.03,
|
|
864
857
|
},
|
|
865
858
|
},
|
|
866
|
-
// Limited to grandfathered accounts: other API keys get HTTP 404 "no
|
|
867
|
-
// longer available to new users", so this model is user-selectable
|
|
868
|
-
// only and no intent column may resolve to it.
|
|
869
859
|
{
|
|
870
860
|
id: "gemini-2.5-flash-lite",
|
|
871
861
|
displayName: "Gemini 2.5 Flash Lite",
|
|
@@ -1826,7 +1816,6 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
1826
1816
|
supportsCaching: true,
|
|
1827
1817
|
supportsVision: true,
|
|
1828
1818
|
supportsToolUse: true,
|
|
1829
|
-
supportsForcedToolChoiceWithThinking: false,
|
|
1830
1819
|
pricing: {
|
|
1831
1820
|
inputPer1mTokens: 0.95,
|
|
1832
1821
|
outputPer1mTokens: 4.0,
|
|
@@ -2639,29 +2628,6 @@ export function modelSupportedEfforts(
|
|
|
2639
2628
|
);
|
|
2640
2629
|
}
|
|
2641
2630
|
|
|
2642
|
-
/**
|
|
2643
|
-
* Whether a provider/model serving surface accepts a forced OpenAI
|
|
2644
|
-
* chat-completions tool choice while thinking is enabled. Unknown providers
|
|
2645
|
-
* and models fail open so custom routes retain their existing request shape
|
|
2646
|
-
* and can rely on the bounded provider-error retry if needed.
|
|
2647
|
-
*/
|
|
2648
|
-
export function supportsForcedToolChoiceWithThinking(
|
|
2649
|
-
providerId: string,
|
|
2650
|
-
modelId: string,
|
|
2651
|
-
): boolean {
|
|
2652
|
-
const provider = PROVIDER_CATALOG.find((entry) => entry.id === providerId);
|
|
2653
|
-
if (!provider) {
|
|
2654
|
-
return true;
|
|
2655
|
-
}
|
|
2656
|
-
const stripDateSuffix = (id: string): string => id.replace(/-\d{8}$/, "");
|
|
2657
|
-
const normalizedModelId = stripDateSuffix(modelId);
|
|
2658
|
-
return !provider.models.some(
|
|
2659
|
-
(model) =>
|
|
2660
|
-
model.supportsForcedToolChoiceWithThinking === false &&
|
|
2661
|
-
(model.id === modelId || stripDateSuffix(model.id) === normalizedModelId),
|
|
2662
|
-
);
|
|
2663
|
-
}
|
|
2664
|
-
|
|
2665
2631
|
/**
|
|
2666
2632
|
* Return the catalog provider that owns a model ID, if known. When multiple
|
|
2667
2633
|
* providers list the same ID (e.g. OpenRouter and the Vercel AI Gateway share
|
|
@@ -11,15 +11,10 @@ const PROVIDER_DEFAULT_MODELS: Record<string, string> = Object.fromEntries(
|
|
|
11
11
|
);
|
|
12
12
|
|
|
13
13
|
// `cost-optimized` is the cheapest model a provider serves, `latency-optimized`
|
|
14
|
-
// the fastest to first token. On anthropic, ollama, fireworks
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// "Serves" means serves to every API key: Google's `gemini-2.5-flash-lite`
|
|
20
|
-
// undercuts every 3.x Flash-Lite but is limited to grandfathered accounts
|
|
21
|
-
// (other keys get HTTP 404 "no longer available to new users"), so the
|
|
22
|
-
// gemini column skips it.
|
|
14
|
+
// the fastest to first token. On anthropic, ollama, fireworks and openai the
|
|
15
|
+
// same model is both, so those columns repeat by construction rather than by
|
|
16
|
+
// oversight (openai's balanced repeats it too: the default-profile templates
|
|
17
|
+
// split those tiers by reasoning effort, not model).
|
|
23
18
|
const PROVIDER_MODEL_INTENTS: Record<string, Record<ModelIntent, string>> = {
|
|
24
19
|
anthropic: {
|
|
25
20
|
balanced: "claude-sonnet-4-6",
|
|
@@ -37,7 +32,7 @@ const PROVIDER_MODEL_INTENTS: Record<string, Record<ModelIntent, string>> = {
|
|
|
37
32
|
},
|
|
38
33
|
gemini: {
|
|
39
34
|
balanced: "gemini-3-flash-preview",
|
|
40
|
-
"cost-optimized": "gemini-
|
|
35
|
+
"cost-optimized": "gemini-2.5-flash-lite",
|
|
41
36
|
"latency-optimized": "gemini-3.1-flash-lite",
|
|
42
37
|
"quality-optimized": "gemini-3.1-pro-preview",
|
|
43
38
|
"vision-optimized": "gemini-3-flash-preview",
|
|
@@ -934,55 +934,6 @@ describe("thinking-mode tool_choice rejection fallback", () => {
|
|
|
934
934
|
expect(text?.text).toBe("ok");
|
|
935
935
|
});
|
|
936
936
|
|
|
937
|
-
test("retries once when Kimi rejects a specified tool_choice in thinking mode", async () => {
|
|
938
|
-
const { provider, requests } = stubProviderWithErrors(
|
|
939
|
-
[
|
|
940
|
-
rejection(
|
|
941
|
-
"tool_choice 'specified' is incompatible with thinking enabled",
|
|
942
|
-
),
|
|
943
|
-
],
|
|
944
|
-
OK_CHUNKS,
|
|
945
|
-
);
|
|
946
|
-
|
|
947
|
-
const response = await provider.sendMessage(
|
|
948
|
-
[{ role: "user", content: [{ type: "text", text: "hi" }] }],
|
|
949
|
-
{
|
|
950
|
-
tools: [
|
|
951
|
-
{
|
|
952
|
-
name: "select_pages",
|
|
953
|
-
description: "Pick relevant memory pages",
|
|
954
|
-
input_schema: { type: "object", properties: {} },
|
|
955
|
-
},
|
|
956
|
-
],
|
|
957
|
-
config: {
|
|
958
|
-
tool_choice: { type: "tool", name: "select_pages" },
|
|
959
|
-
effort: "high",
|
|
960
|
-
},
|
|
961
|
-
},
|
|
962
|
-
);
|
|
963
|
-
|
|
964
|
-
expect(requests).toHaveLength(2);
|
|
965
|
-
const first = requests[0] as {
|
|
966
|
-
tool_choice?: { type: string; function: { name: string } };
|
|
967
|
-
reasoning_effort?: string;
|
|
968
|
-
};
|
|
969
|
-
const second = requests[1] as {
|
|
970
|
-
tool_choice?: unknown;
|
|
971
|
-
reasoning_effort?: string;
|
|
972
|
-
};
|
|
973
|
-
expect(first.tool_choice).toEqual({
|
|
974
|
-
type: "function",
|
|
975
|
-
function: { name: "select_pages" },
|
|
976
|
-
});
|
|
977
|
-
expect(first.reasoning_effort).toBe("high");
|
|
978
|
-
expect(second.tool_choice).toBeUndefined();
|
|
979
|
-
expect(second.reasoning_effort).toBe("high");
|
|
980
|
-
const text = response.content.find((b) => b.type === "text") as
|
|
981
|
-
| { type: "text"; text: string }
|
|
982
|
-
| undefined;
|
|
983
|
-
expect(text?.text).toBe("ok");
|
|
984
|
-
});
|
|
985
|
-
|
|
986
937
|
test("retries once for an OpenRouter-wrapped thinking-mode tool_choice rejection", async () => {
|
|
987
938
|
const wrapped = new OpenAI.APIError(
|
|
988
939
|
400,
|
|
@@ -1190,80 +1141,33 @@ describe("unknown assistant reasoning field rejection fallback", () => {
|
|
|
1190
1141
|
},
|
|
1191
1142
|
];
|
|
1192
1143
|
|
|
1193
|
-
test
|
|
1194
|
-
[
|
|
1195
|
-
"a strict schema",
|
|
1196
|
-
"Additional properties are not allowed ('reasoning_content' was unexpected)",
|
|
1197
|
-
],
|
|
1198
|
-
["Groq", "property 'reasoning_content' is unsupported"],
|
|
1199
|
-
])(
|
|
1200
|
-
"retries once without reasoning_content when %s rejects it",
|
|
1201
|
-
async (_upstream, message) => {
|
|
1202
|
-
const { provider, requests } = stubProviderWithErrors(
|
|
1203
|
-
[rejection(message)],
|
|
1204
|
-
OK_CHUNKS,
|
|
1205
|
-
{ assistantReasoningField: "reasoning_content" },
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
const response = await provider.sendMessage(thinkingHistory);
|
|
1209
|
-
|
|
1210
|
-
expect(requests).toHaveLength(2);
|
|
1211
|
-
const first = requests[0] as {
|
|
1212
|
-
messages: Array<{ reasoning_content?: string; content: string | null }>;
|
|
1213
|
-
};
|
|
1214
|
-
const second = requests[1] as {
|
|
1215
|
-
messages: Array<{ reasoning_content?: string; content: string | null }>;
|
|
1216
|
-
};
|
|
1217
|
-
expect(first.messages[0].reasoning_content).toBe("hidden chain");
|
|
1218
|
-
expect(second.messages[0].reasoning_content).toBeUndefined();
|
|
1219
|
-
expect(second.messages[0].content).toBe("answer");
|
|
1220
|
-
const text = response.content.find((b) => b.type === "text") as
|
|
1221
|
-
| { type: "text"; text: string }
|
|
1222
|
-
| undefined;
|
|
1223
|
-
expect(text?.text).toBe("ok");
|
|
1224
|
-
},
|
|
1225
|
-
);
|
|
1226
|
-
|
|
1227
|
-
test("preserves assistant tool calls when stripping an unsupported reasoning_content", async () => {
|
|
1144
|
+
test("retries once without reasoning_content when a strict schema rejects it", async () => {
|
|
1228
1145
|
const { provider, requests } = stubProviderWithErrors(
|
|
1229
|
-
[
|
|
1146
|
+
[
|
|
1147
|
+
rejection(
|
|
1148
|
+
"Additional properties are not allowed ('reasoning_content' was unexpected)",
|
|
1149
|
+
),
|
|
1150
|
+
],
|
|
1230
1151
|
OK_CHUNKS,
|
|
1231
1152
|
{ assistantReasoningField: "reasoning_content" },
|
|
1232
1153
|
);
|
|
1233
1154
|
|
|
1234
|
-
await provider.sendMessage(
|
|
1235
|
-
{
|
|
1236
|
-
role: "assistant",
|
|
1237
|
-
content: [
|
|
1238
|
-
{ type: "thinking", thinking: "hidden chain", signature: "" },
|
|
1239
|
-
{
|
|
1240
|
-
type: "tool_use",
|
|
1241
|
-
id: "call_1",
|
|
1242
|
-
name: "lookup",
|
|
1243
|
-
input: { q: "x" },
|
|
1244
|
-
},
|
|
1245
|
-
],
|
|
1246
|
-
},
|
|
1247
|
-
{
|
|
1248
|
-
role: "user",
|
|
1249
|
-
content: [
|
|
1250
|
-
{ type: "tool_result", tool_use_id: "call_1", content: "found" },
|
|
1251
|
-
],
|
|
1252
|
-
},
|
|
1253
|
-
]);
|
|
1155
|
+
const response = await provider.sendMessage(thinkingHistory);
|
|
1254
1156
|
|
|
1255
1157
|
expect(requests).toHaveLength(2);
|
|
1158
|
+
const first = requests[0] as {
|
|
1159
|
+
messages: Array<{ reasoning_content?: string; content: string | null }>;
|
|
1160
|
+
};
|
|
1256
1161
|
const second = requests[1] as {
|
|
1257
|
-
messages: Array<{
|
|
1258
|
-
role: string;
|
|
1259
|
-
reasoning_content?: string;
|
|
1260
|
-
tool_calls?: Array<{ id: string; function: { name: string } }>;
|
|
1261
|
-
}>;
|
|
1162
|
+
messages: Array<{ reasoning_content?: string; content: string | null }>;
|
|
1262
1163
|
};
|
|
1263
|
-
|
|
1264
|
-
expect(
|
|
1265
|
-
expect(
|
|
1266
|
-
|
|
1164
|
+
expect(first.messages[0].reasoning_content).toBe("hidden chain");
|
|
1165
|
+
expect(second.messages[0].reasoning_content).toBeUndefined();
|
|
1166
|
+
expect(second.messages[0].content).toBe("answer");
|
|
1167
|
+
const text = response.content.find((b) => b.type === "text") as
|
|
1168
|
+
| { type: "text"; text: string }
|
|
1169
|
+
| undefined;
|
|
1170
|
+
expect(text?.text).toBe("ok");
|
|
1267
1171
|
});
|
|
1268
1172
|
|
|
1269
1173
|
test("does not strip reasoning_content on a must-be-passed-back error", async () => {
|
|
@@ -1285,38 +1189,6 @@ describe("unknown assistant reasoning field rejection fallback", () => {
|
|
|
1285
1189
|
).toBe("hidden chain");
|
|
1286
1190
|
});
|
|
1287
1191
|
|
|
1288
|
-
test("does not strip reasoning_content on a 429 output-token limit", async () => {
|
|
1289
|
-
const { provider, requests } = stubProviderWithErrors(
|
|
1290
|
-
[
|
|
1291
|
-
rejection(
|
|
1292
|
-
"Rate limit reached for model `qwen/qwen3-32b` in organization `org_x` on tokens per minute (TPM): Limit 1000, Requested 4000.",
|
|
1293
|
-
429,
|
|
1294
|
-
),
|
|
1295
|
-
],
|
|
1296
|
-
OK_CHUNKS,
|
|
1297
|
-
{ assistantReasoningField: "reasoning_content" },
|
|
1298
|
-
);
|
|
1299
|
-
|
|
1300
|
-
await expect(provider.sendMessage(thinkingHistory)).rejects.toThrow();
|
|
1301
|
-
expect(requests).toHaveLength(1);
|
|
1302
|
-
});
|
|
1303
|
-
|
|
1304
|
-
test("does not strip reasoning_content on a 413 input-token limit", async () => {
|
|
1305
|
-
const { provider, requests } = stubProviderWithErrors(
|
|
1306
|
-
[
|
|
1307
|
-
rejection(
|
|
1308
|
-
"Request too large for model `qwen/qwen3-32b` in organization `org_x` on tokens per minute (TPM): Limit 7000, Requested 24936.",
|
|
1309
|
-
413,
|
|
1310
|
-
),
|
|
1311
|
-
],
|
|
1312
|
-
OK_CHUNKS,
|
|
1313
|
-
{ assistantReasoningField: "reasoning_content" },
|
|
1314
|
-
);
|
|
1315
|
-
|
|
1316
|
-
await expect(provider.sendMessage(thinkingHistory)).rejects.toThrow();
|
|
1317
|
-
expect(requests).toHaveLength(1);
|
|
1318
|
-
});
|
|
1319
|
-
|
|
1320
1192
|
test("does not retry unknown-field 500s", async () => {
|
|
1321
1193
|
const { provider, requests } = stubProviderWithErrors(
|
|
1322
1194
|
[
|