@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
|
@@ -26,14 +26,13 @@ const USER_MESSAGE: Message[] = [
|
|
|
26
26
|
*/
|
|
27
27
|
function stubChatProvider(
|
|
28
28
|
options?: ConstructorParameters<typeof OpenAIChatCompletionsProvider>[2],
|
|
29
|
-
model = "test-model",
|
|
30
29
|
): {
|
|
31
30
|
provider: OpenAIChatCompletionsProvider;
|
|
32
31
|
requests: Array<Record<string, unknown>>;
|
|
33
32
|
} {
|
|
34
33
|
const provider = new OpenAIChatCompletionsProvider(
|
|
35
34
|
"test-key",
|
|
36
|
-
model,
|
|
35
|
+
"test-model",
|
|
37
36
|
options,
|
|
38
37
|
);
|
|
39
38
|
const requests: Array<Record<string, unknown>> = [];
|
|
@@ -236,87 +235,6 @@ describe("OpenAIChatCompletionsProvider tool_choice wiring", () => {
|
|
|
236
235
|
});
|
|
237
236
|
});
|
|
238
237
|
|
|
239
|
-
test("omits a forced tool choice for OpenRouter Kimi K2.6 with thinking", async () => {
|
|
240
|
-
const { provider, requests } = stubChatProvider(
|
|
241
|
-
{ providerName: "openrouter" },
|
|
242
|
-
"moonshotai/kimi-k2.6-20260420",
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
await provider.sendMessage(USER_MESSAGE, {
|
|
246
|
-
tools: TOOLS,
|
|
247
|
-
config: { tool_choice: { type: "tool", name: "bash" }, effort: "high" },
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
expect(requests).toHaveLength(1);
|
|
251
|
-
expect(requests[0].reasoning_effort).toBe("high");
|
|
252
|
-
expect(requests[0].tool_choice).toBeUndefined();
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
test("omits required for OpenRouter Kimi K2.6 with thinking", async () => {
|
|
256
|
-
const { provider, requests } = stubChatProvider(
|
|
257
|
-
{ providerName: "openrouter" },
|
|
258
|
-
"moonshotai/kimi-k2.6-20260420",
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
await provider.sendMessage(USER_MESSAGE, {
|
|
262
|
-
tools: TOOLS,
|
|
263
|
-
config: { tool_choice: { type: "any" }, effort: "high" },
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
expect(requests).toHaveLength(1);
|
|
267
|
-
expect(requests[0].reasoning_effort).toBe("high");
|
|
268
|
-
expect(requests[0].tool_choice).toBeUndefined();
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
test("keeps tool_choice none for OpenRouter Kimi K2.6 with thinking", async () => {
|
|
272
|
-
const { provider, requests } = stubChatProvider(
|
|
273
|
-
{ providerName: "openrouter" },
|
|
274
|
-
"moonshotai/kimi-k2.6-20260420",
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
await provider.sendMessage(USER_MESSAGE, {
|
|
278
|
-
tools: TOOLS,
|
|
279
|
-
config: { tool_choice: { type: "none" }, effort: "high" },
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
expect(requests[0].reasoning_effort).toBe("high");
|
|
283
|
-
expect(requests[0].tool_choice).toBe("none");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("keeps a forced tool choice for OpenRouter Kimi K2.6 when thinking is off", async () => {
|
|
287
|
-
const { provider, requests } = stubChatProvider(
|
|
288
|
-
{ providerName: "openrouter" },
|
|
289
|
-
"moonshotai/kimi-k2.6-20260420",
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
await provider.sendMessage(USER_MESSAGE, {
|
|
293
|
-
tools: TOOLS,
|
|
294
|
-
config: { tool_choice: { type: "tool", name: "bash" } },
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
expect(requests[0].tool_choice).toEqual({
|
|
298
|
-
type: "function",
|
|
299
|
-
function: { name: "bash" },
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
test("keeps a forced tool choice for Vercel Kimi K2.6 with thinking", async () => {
|
|
304
|
-
const { provider, requests } = stubChatProvider(
|
|
305
|
-
{ providerName: "vercel-ai-gateway" },
|
|
306
|
-
"moonshotai/kimi-k2.6",
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
await provider.sendMessage(USER_MESSAGE, {
|
|
310
|
-
tools: TOOLS,
|
|
311
|
-
config: { tool_choice: { type: "tool", name: "bash" }, effort: "high" },
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
expect(requests[0].tool_choice).toEqual({
|
|
315
|
-
type: "function",
|
|
316
|
-
function: { name: "bash" },
|
|
317
|
-
});
|
|
318
|
-
});
|
|
319
|
-
|
|
320
238
|
test("omits every tool_choice in thinking mode when omitToolChoiceWhenReasoning is on", async () => {
|
|
321
239
|
const { provider, requests } = stubChatProvider({
|
|
322
240
|
omitToolChoiceWhenReasoning: true,
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
mediaSourceByteLength,
|
|
18
18
|
resolveMediaReferences,
|
|
19
19
|
} from "../media-resolve.js";
|
|
20
|
-
import { supportsForcedToolChoiceWithThinking } from "../model-catalog.js";
|
|
21
20
|
import { PLACEHOLDER_EMPTY_TURN } from "../placeholder-sentinels.js";
|
|
22
21
|
import { recordProviderRequestDiagnostics } from "../request-diagnostics.js";
|
|
23
22
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
@@ -28,7 +27,6 @@ import type {
|
|
|
28
27
|
Provider,
|
|
29
28
|
ProviderResponse,
|
|
30
29
|
SendMessageOptions,
|
|
31
|
-
ToolUseContent,
|
|
32
30
|
} from "../types.js";
|
|
33
31
|
import {
|
|
34
32
|
ContextOverflowError,
|
|
@@ -53,15 +51,6 @@ import {
|
|
|
53
51
|
coerceObjectParamsToJsonString,
|
|
54
52
|
decodeCoercedObjectArgs,
|
|
55
53
|
} from "./coerce-object-args.js";
|
|
56
|
-
import {
|
|
57
|
-
applyGemini3UnsignedToolCallFallback,
|
|
58
|
-
attachGoogleThoughtSignatureIfNeeded,
|
|
59
|
-
classifyGoogleThoughtSignatureRetry,
|
|
60
|
-
geminiThoughtSignaturesByToolCallId,
|
|
61
|
-
type GoogleToolCallExtraContent,
|
|
62
|
-
thoughtSignatureFromToolUseMetadata,
|
|
63
|
-
toolUseMetadataFromChatCompletionsDelta,
|
|
64
|
-
} from "./google-thought-signature.js";
|
|
65
54
|
import {
|
|
66
55
|
isOpenAICompatInlineAudio,
|
|
67
56
|
OPENAI_COMPAT_MAX_INLINE_AUDIO_BYTES,
|
|
@@ -215,13 +204,7 @@ const log = getLogger("chat-completions");
|
|
|
215
204
|
/** Wire-level reasoning_effort values. The OpenAI SDK type doesn't include
|
|
216
205
|
* `"max"`, but Fireworks accepts it for DeepSeek V4; the assignment to
|
|
217
206
|
* `params.reasoning_effort` casts through this union. */
|
|
218
|
-
export type ReasoningEffortWire =
|
|
219
|
-
| "none"
|
|
220
|
-
| "low"
|
|
221
|
-
| "medium"
|
|
222
|
-
| "high"
|
|
223
|
-
| "xhigh"
|
|
224
|
-
| "max";
|
|
207
|
+
export type ReasoningEffortWire = "none" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
225
208
|
|
|
226
209
|
const REASONING_EFFORT_RANK: Record<ReasoningEffortWire, number> = {
|
|
227
210
|
none: 0,
|
|
@@ -405,15 +388,9 @@ export function isThinkingEnabledOnWire(params: unknown): boolean {
|
|
|
405
388
|
* rejected it because thinking/reasoning mode forbids that parameter.
|
|
406
389
|
* DeepSeek thinking mode 400s with `Thinking mode does not support this
|
|
407
390
|
* tool_choice` for any explicit value, including `"auto"` and `"none"`.
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
* instead of failing over to a different backend.
|
|
391
|
+
* One retry without `tool_choice` lets the same provider succeed instead of
|
|
392
|
+
* failing over to a different backend.
|
|
411
393
|
*/
|
|
412
|
-
const THINKING_MODE_TOOL_CHOICE_REJECTION_PATTERNS: RegExp[] = [
|
|
413
|
-
/does not support this tool_choice/i,
|
|
414
|
-
/tool_choice\s+'specified'\s+is incompatible with thinking/i,
|
|
415
|
-
];
|
|
416
|
-
|
|
417
394
|
function isThinkingModeToolChoiceRejection(
|
|
418
395
|
error: unknown,
|
|
419
396
|
params: unknown,
|
|
@@ -425,9 +402,8 @@ function isThinkingModeToolChoiceRejection(
|
|
|
425
402
|
if (!isClientErrorStatus(error)) {
|
|
426
403
|
return false;
|
|
427
404
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
pattern.test(haystack),
|
|
405
|
+
return /does not support this tool_choice/i.test(
|
|
406
|
+
openaiCompatErrorHaystack(error),
|
|
431
407
|
);
|
|
432
408
|
}
|
|
433
409
|
|
|
@@ -565,10 +541,8 @@ function isMissingReasoningContentRejection(
|
|
|
565
541
|
|
|
566
542
|
/**
|
|
567
543
|
* True when the request included an assistant `reasoning` / `reasoning_content`
|
|
568
|
-
* extra and the provider rejected it as an unknown
|
|
569
|
-
*
|
|
570
|
-
* schema succeed. Groq phrases this as
|
|
571
|
-
* `property 'reasoning_content' is unsupported`.
|
|
544
|
+
* extra and the provider rejected it as an unknown message property. One retry
|
|
545
|
+
* without those extras lets a strict Chat Completions schema succeed.
|
|
572
546
|
*/
|
|
573
547
|
function isUnknownAssistantReasoningFieldRejection(
|
|
574
548
|
error: unknown,
|
|
@@ -587,7 +561,7 @@ function isUnknownAssistantReasoningFieldRejection(
|
|
|
587
561
|
if (!haystackNamesAssistantReasoningField(haystack)) {
|
|
588
562
|
return false;
|
|
589
563
|
}
|
|
590
|
-
return /unknown|unexpected|unrecognized|
|
|
564
|
+
return /unknown|unexpected|unrecognized|additional propert|extra (?:field|property)|not (?:a )?valid|invalid (?:argument|parameter|field|property)/i.test(
|
|
591
565
|
haystack,
|
|
592
566
|
);
|
|
593
567
|
}
|
|
@@ -660,82 +634,6 @@ function flattenContentPartsToStrings(params: unknown): boolean {
|
|
|
660
634
|
return flattened;
|
|
661
635
|
}
|
|
662
636
|
|
|
663
|
-
type OpenAICompatRetryKind =
|
|
664
|
-
| "reasoning-opt-out"
|
|
665
|
-
| "thinking-tool-choice"
|
|
666
|
-
| "missing-reasoning-content"
|
|
667
|
-
| "unknown-reasoning-field"
|
|
668
|
-
| "missing-thought-signature"
|
|
669
|
-
| "unknown-extra-content"
|
|
670
|
-
| "chat-template";
|
|
671
|
-
|
|
672
|
-
function classifyOpenAICompatRetry(
|
|
673
|
-
error: unknown,
|
|
674
|
-
params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming,
|
|
675
|
-
thoughtSignaturesByCallId: ReadonlyMap<string, string>,
|
|
676
|
-
): { kind: OpenAICompatRetryKind; message: string; apply: () => void } | null {
|
|
677
|
-
if (isReasoningOptOutRejection(error, params)) {
|
|
678
|
-
return {
|
|
679
|
-
kind: "reasoning-opt-out",
|
|
680
|
-
message:
|
|
681
|
-
"Model rejected the explicit reasoning opt-out; retrying without reasoning params",
|
|
682
|
-
apply: () => {
|
|
683
|
-
delete params.reasoning_effort;
|
|
684
|
-
delete (params as unknown as Record<string, unknown>).reasoning;
|
|
685
|
-
},
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
if (isThinkingModeToolChoiceRejection(error, params)) {
|
|
689
|
-
return {
|
|
690
|
-
kind: "thinking-tool-choice",
|
|
691
|
-
message:
|
|
692
|
-
"Upstream rejected tool_choice in thinking mode; retrying without tool_choice",
|
|
693
|
-
apply: () => {
|
|
694
|
-
delete params.tool_choice;
|
|
695
|
-
},
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
if (isMissingReasoningContentRejection(error, params)) {
|
|
699
|
-
return {
|
|
700
|
-
kind: "missing-reasoning-content",
|
|
701
|
-
message:
|
|
702
|
-
"Upstream requires reasoning_content round-trip; retrying with empty field on assistant messages",
|
|
703
|
-
apply: () => {
|
|
704
|
-
backfillEmptyReasoningContent(params);
|
|
705
|
-
},
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
if (isUnknownAssistantReasoningFieldRejection(error, params)) {
|
|
709
|
-
return {
|
|
710
|
-
kind: "unknown-reasoning-field",
|
|
711
|
-
message:
|
|
712
|
-
"Upstream rejected assistant reasoning field; retrying without it",
|
|
713
|
-
apply: () => {
|
|
714
|
-
stripAssistantReasoningFields(params);
|
|
715
|
-
},
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
const thoughtSignatureRetry = classifyGoogleThoughtSignatureRetry(params, {
|
|
719
|
-
isClientError: isClientErrorStatus(error),
|
|
720
|
-
haystack: openaiCompatErrorHaystack(error),
|
|
721
|
-
capturedByCallId: thoughtSignaturesByCallId,
|
|
722
|
-
});
|
|
723
|
-
if (thoughtSignatureRetry) {
|
|
724
|
-
return thoughtSignatureRetry;
|
|
725
|
-
}
|
|
726
|
-
if (isChatTemplateRejection(error, params)) {
|
|
727
|
-
return {
|
|
728
|
-
kind: "chat-template",
|
|
729
|
-
message:
|
|
730
|
-
"Upstream chat template rejected structured message content; retrying with flattened plain-text content",
|
|
731
|
-
apply: () => {
|
|
732
|
-
flattenContentPartsToStrings(params);
|
|
733
|
-
},
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
return null;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
637
|
/**
|
|
740
638
|
* Translate the neutral (Anthropic-shaped) `tool_choice` carried on the call
|
|
741
639
|
* config into the OpenAI chat-completions wire format. Callers express
|
|
@@ -876,13 +774,10 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
876
774
|
const coercedObjectKeys = new Map<string, string[]>();
|
|
877
775
|
|
|
878
776
|
try {
|
|
879
|
-
const thoughtSignaturesByCallId =
|
|
880
|
-
geminiThoughtSignaturesByToolCallId(messages);
|
|
881
777
|
const openaiMessages = await this.toOpenAIMessages(
|
|
882
778
|
messages,
|
|
883
779
|
systemPrompt,
|
|
884
780
|
requestSupportsInlineAudio(modelOverride ?? this.model),
|
|
885
|
-
modelOverride ?? this.model,
|
|
886
781
|
);
|
|
887
782
|
|
|
888
783
|
recordProviderRequestDiagnostics({
|
|
@@ -979,18 +874,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
979
874
|
const thinkingOn = isThinkingEnabledOnWire(params);
|
|
980
875
|
const skipAutoDefault = thinkingOn && toolChoice === "auto";
|
|
981
876
|
const skipAllChoices = thinkingOn && this.omitToolChoiceWhenReasoning;
|
|
982
|
-
|
|
983
|
-
thinkingOn &&
|
|
984
|
-
!supportsForcedToolChoiceWithThinking(
|
|
985
|
-
this.name,
|
|
986
|
-
modelOverride ?? this.model,
|
|
987
|
-
) &&
|
|
988
|
-
(toolChoice === "required" || typeof toolChoice === "object");
|
|
989
|
-
if (
|
|
990
|
-
!skipAutoDefault &&
|
|
991
|
-
!skipAllChoices &&
|
|
992
|
-
!skipIncompatibleForcedChoice
|
|
993
|
-
) {
|
|
877
|
+
if (!skipAutoDefault && !skipAllChoices) {
|
|
994
878
|
params.tool_choice = toolChoice;
|
|
995
879
|
}
|
|
996
880
|
}
|
|
@@ -1089,12 +973,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1089
973
|
|
|
1090
974
|
const toolCallMap = new Map<
|
|
1091
975
|
number,
|
|
1092
|
-
{
|
|
1093
|
-
id: string;
|
|
1094
|
-
name: string;
|
|
1095
|
-
args: string;
|
|
1096
|
-
providerMetadata?: ToolUseContent["providerMetadata"];
|
|
1097
|
-
}
|
|
976
|
+
{ id: string; name: string; args: string }
|
|
1098
977
|
>();
|
|
1099
978
|
const toolProgress = createToolProgressEmitter(onEvent);
|
|
1100
979
|
let finishReason = "unknown";
|
|
@@ -1122,31 +1001,68 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1122
1001
|
? { headers: requestHeaders }
|
|
1123
1002
|
: {}),
|
|
1124
1003
|
});
|
|
1125
|
-
const attemptedCompatRetries = new Set<OpenAICompatRetryKind>();
|
|
1126
1004
|
let stream: Awaited<ReturnType<typeof createStream>>;
|
|
1127
|
-
|
|
1128
|
-
|
|
1005
|
+
try {
|
|
1006
|
+
stream = await createStream();
|
|
1007
|
+
} catch (error) {
|
|
1008
|
+
if (isReasoningOptOutRejection(error, params)) {
|
|
1009
|
+
log.warn(
|
|
1010
|
+
{
|
|
1011
|
+
provider: this.name,
|
|
1012
|
+
model: modelOverride ?? this.model,
|
|
1013
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1014
|
+
},
|
|
1015
|
+
"Model rejected the explicit reasoning opt-out; retrying without reasoning params",
|
|
1016
|
+
);
|
|
1017
|
+
delete params.reasoning_effort;
|
|
1018
|
+
delete (params as unknown as Record<string, unknown>).reasoning;
|
|
1129
1019
|
stream = await createStream();
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1020
|
+
} else if (isThinkingModeToolChoiceRejection(error, params)) {
|
|
1021
|
+
log.warn(
|
|
1022
|
+
{
|
|
1023
|
+
provider: this.name,
|
|
1024
|
+
model: modelOverride ?? this.model,
|
|
1025
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1026
|
+
},
|
|
1027
|
+
"Upstream rejected tool_choice in thinking mode; retrying without tool_choice",
|
|
1136
1028
|
);
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1029
|
+
delete params.tool_choice;
|
|
1030
|
+
stream = await createStream();
|
|
1031
|
+
} else if (isMissingReasoningContentRejection(error, params)) {
|
|
1032
|
+
log.warn(
|
|
1033
|
+
{
|
|
1034
|
+
provider: this.name,
|
|
1035
|
+
model: modelOverride ?? this.model,
|
|
1036
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1037
|
+
},
|
|
1038
|
+
"Upstream requires reasoning_content round-trip; retrying with empty field on assistant messages",
|
|
1039
|
+
);
|
|
1040
|
+
backfillEmptyReasoningContent(params);
|
|
1041
|
+
stream = await createStream();
|
|
1042
|
+
} else if (isUnknownAssistantReasoningFieldRejection(error, params)) {
|
|
1141
1043
|
log.warn(
|
|
1142
1044
|
{
|
|
1143
1045
|
provider: this.name,
|
|
1144
1046
|
model: modelOverride ?? this.model,
|
|
1145
1047
|
error: error instanceof Error ? error.message : String(error),
|
|
1146
1048
|
},
|
|
1147
|
-
|
|
1049
|
+
"Upstream rejected assistant reasoning field; retrying without it",
|
|
1148
1050
|
);
|
|
1149
|
-
|
|
1051
|
+
stripAssistantReasoningFields(params);
|
|
1052
|
+
stream = await createStream();
|
|
1053
|
+
} else if (isChatTemplateRejection(error, params)) {
|
|
1054
|
+
log.warn(
|
|
1055
|
+
{
|
|
1056
|
+
provider: this.name,
|
|
1057
|
+
model: modelOverride ?? this.model,
|
|
1058
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1059
|
+
},
|
|
1060
|
+
"Upstream chat template rejected structured message content; retrying with flattened plain-text content",
|
|
1061
|
+
);
|
|
1062
|
+
flattenContentPartsToStrings(params);
|
|
1063
|
+
stream = await createStream();
|
|
1064
|
+
} else {
|
|
1065
|
+
throw error;
|
|
1150
1066
|
}
|
|
1151
1067
|
}
|
|
1152
1068
|
|
|
@@ -1234,14 +1150,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1234
1150
|
entry.args,
|
|
1235
1151
|
);
|
|
1236
1152
|
}
|
|
1237
|
-
const providerMetadata =
|
|
1238
|
-
toolUseMetadataFromChatCompletionsDelta(tc);
|
|
1239
|
-
if (
|
|
1240
|
-
providerMetadata &&
|
|
1241
|
-
!thoughtSignatureFromToolUseMetadata(entry.providerMetadata)
|
|
1242
|
-
) {
|
|
1243
|
-
entry.providerMetadata = providerMetadata;
|
|
1244
|
-
}
|
|
1245
1153
|
}
|
|
1246
1154
|
}
|
|
1247
1155
|
|
|
@@ -1363,9 +1271,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1363
1271
|
id: tc.id,
|
|
1364
1272
|
name: tc.name,
|
|
1365
1273
|
input,
|
|
1366
|
-
...(tc.providerMetadata
|
|
1367
|
-
? { providerMetadata: tc.providerMetadata }
|
|
1368
|
-
: {}),
|
|
1369
1274
|
});
|
|
1370
1275
|
}
|
|
1371
1276
|
|
|
@@ -1379,19 +1284,11 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1379
1284
|
content: contentText || null,
|
|
1380
1285
|
tool_calls:
|
|
1381
1286
|
toolCallMap.size > 0
|
|
1382
|
-
? Array.from(toolCallMap.values()).map((tc) =>
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
function: { name: tc.name, arguments: tc.args },
|
|
1388
|
-
},
|
|
1389
|
-
thoughtSignatureFromToolUseMetadata(
|
|
1390
|
-
tc.providerMetadata,
|
|
1391
|
-
),
|
|
1392
|
-
modelOverride ?? this.model,
|
|
1393
|
-
),
|
|
1394
|
-
)
|
|
1287
|
+
? Array.from(toolCallMap.values()).map((tc) => ({
|
|
1288
|
+
id: tc.id,
|
|
1289
|
+
type: "function",
|
|
1290
|
+
function: { name: tc.name, arguments: tc.args },
|
|
1291
|
+
}))
|
|
1395
1292
|
: undefined,
|
|
1396
1293
|
},
|
|
1397
1294
|
finish_reason: finishReason,
|
|
@@ -1595,7 +1492,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1595
1492
|
messages: Message[],
|
|
1596
1493
|
systemPrompt?: string,
|
|
1597
1494
|
audioInputEnabled = false,
|
|
1598
|
-
model = this.model,
|
|
1599
1495
|
): Promise<OpenAI.Chat.Completions.ChatCompletionMessageParam[]> {
|
|
1600
1496
|
// Swap any persisted attachment references back to inline base64 before
|
|
1601
1497
|
// serializing, so the block transforms below can read `source.data`.
|
|
@@ -1617,7 +1513,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1617
1513
|
const emittedToolCallIds = new Set<string>();
|
|
1618
1514
|
for (const msg of messages) {
|
|
1619
1515
|
if (msg.role === "assistant") {
|
|
1620
|
-
const assistantMessage = this.toOpenAIAssistantMessage(msg
|
|
1516
|
+
const assistantMessage = this.toOpenAIAssistantMessage(msg);
|
|
1621
1517
|
for (const toolCall of assistantMessage.tool_calls ?? []) {
|
|
1622
1518
|
emittedToolCallIds.add(toolCall.id);
|
|
1623
1519
|
}
|
|
@@ -1695,14 +1591,11 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1695
1591
|
/** Convert an assistant message with text + tool_use blocks to OpenAI format. */
|
|
1696
1592
|
private toOpenAIAssistantMessage(
|
|
1697
1593
|
msg: Message,
|
|
1698
|
-
model: string,
|
|
1699
1594
|
): OpenAI.Chat.Completions.ChatCompletionAssistantMessageParam {
|
|
1700
1595
|
const textParts: string[] = [];
|
|
1701
1596
|
const reasoningParts: string[] = [];
|
|
1702
|
-
const toolCalls:
|
|
1703
|
-
|
|
1704
|
-
GoogleToolCallExtraContent
|
|
1705
|
-
> = [];
|
|
1597
|
+
const toolCalls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[] =
|
|
1598
|
+
[];
|
|
1706
1599
|
|
|
1707
1600
|
for (const block of msg.content) {
|
|
1708
1601
|
switch (block.type) {
|
|
@@ -1716,20 +1609,14 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1716
1609
|
}
|
|
1717
1610
|
break;
|
|
1718
1611
|
case "tool_use":
|
|
1719
|
-
toolCalls.push(
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
},
|
|
1728
|
-
},
|
|
1729
|
-
thoughtSignatureFromToolUseMetadata(block.providerMetadata),
|
|
1730
|
-
model,
|
|
1731
|
-
),
|
|
1732
|
-
);
|
|
1612
|
+
toolCalls.push({
|
|
1613
|
+
id: block.id,
|
|
1614
|
+
type: "function",
|
|
1615
|
+
function: {
|
|
1616
|
+
name: block.name,
|
|
1617
|
+
arguments: JSON.stringify(block.input),
|
|
1618
|
+
},
|
|
1619
|
+
});
|
|
1733
1620
|
break;
|
|
1734
1621
|
case "server_tool_use":
|
|
1735
1622
|
textParts.push(`[Web search: ${block.name}]`);
|
|
@@ -1748,7 +1635,6 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
1748
1635
|
};
|
|
1749
1636
|
|
|
1750
1637
|
if (toolCalls.length > 0) {
|
|
1751
|
-
applyGemini3UnsignedToolCallFallback(toolCalls, model);
|
|
1752
1638
|
result.tool_calls = toolCalls;
|
|
1753
1639
|
}
|
|
1754
1640
|
|
|
@@ -14,6 +14,10 @@ export const CODEX_SUBSCRIPTION_MODEL_IDS: ReadonlySet<string> = new Set([
|
|
|
14
14
|
"gpt-5.6-terra",
|
|
15
15
|
"gpt-5.6-luna",
|
|
16
16
|
"gpt-5.5",
|
|
17
|
+
// OpenAI retires these two from ChatGPT sign-in on 2026-08-31; API-key
|
|
18
|
+
// auth is unaffected.
|
|
19
|
+
"gpt-5.4",
|
|
20
|
+
"gpt-5.4-mini",
|
|
17
21
|
]);
|
|
18
22
|
|
|
19
23
|
/** True when `model` is allowlisted for Codex subscription routing. */
|
package/src/runtime/AGENTS.md
CHANGED
|
@@ -12,8 +12,6 @@ The single HTTP send endpoint is `POST /v1/messages`. Key behaviors:
|
|
|
12
12
|
|
|
13
13
|
Do NOT add new send endpoints. All message ingress should go through `POST /v1/messages` (HTTP).
|
|
14
14
|
|
|
15
|
-
`POST /v1/channels/send` is not ingress: it is outbound delivery, the assistant posting text to a channel chat. It runs `sendChannelText` (`runtime/channel-send.ts`), the one send implementation for every channel whose transport declares proactive addressing (`ChannelTransport.addressFor`), and the messaging tool's channel branch runs the same function in-process, as the CLI's channel send door does over the route. A model-directed channel send goes through that function or it is not recorded; do not add a provider-side send for a channel that has a transport. The route names no sending turn: only the in-process tool call can claim a send landed in the turn's own chat, so everything sent through the route is recorded.
|
|
16
|
-
|
|
17
15
|
**`interrupt-on-send`: a send may stop the running turn instead of queueing behind it.** With the flag on, a busy conversation is handed to `interruptRunningTurn` (`daemon/conversation-interrupt.ts`), which aborts the turn with `preempted_by_new_message`, waits for it to release the processing lock AND for its turn-boundary commit to finish, repairs the abandoned `tool_use` blocks with a persisted synthetic `tool_result`, and answers `released`. The route then falls through to the code an idle conversation already uses, so there is one turn dispatch rather than a second one for interrupts. The queue is not discarded: it may hold another actor's messages.
|
|
18
16
|
|
|
19
17
|
**The handover runs off the response, not on it.** Fire-and-forget is not suspended for an interrupt. The eligibility decision is synchronous (`classifyInterruptEligibility`), so the route answers `202 { accepted, requestId }` the moment it accepts the message, then runs the abort, the release wait, the commit wait, the repair, the persist and the dispatch in a detached task. Holding the request would cost the abort budget (`ABORT_RELEASE_WAIT_MS`) plus the turn-boundary commit wait, long enough for a client to time out and retry a message the daemon is still placing. That 202 carries `messageId` as well as `requestId`, and they are the same value: a user turn persists its row under its `requestId` (`persistUserMessage` passes `id: requestId`), which is what lets the id be answered before the row exists. Both are required, not decorative: `postChatMessage` rejects an accepted, non-queued response without a string `messageId` and the client drops the optimistic row. Clients reconcile that row on `user_message_echo`. Two rules for anything added to that task: it must not be able to drop the message (every failure path falls back to `queueSend`, which never takes the enqueue's idle fast path, and a queue that refuses the fallback is reported to the sender as a `QUEUE_FULL` error keyed on the `requestId` the 202 carried, since the 429 itself reaches nobody), and a duplicate `clientMessageId` is answered from the existing row BEFORE the abort, since the insert's own dedup settles too late to un-abort a turn.
|
|
@@ -142,7 +142,9 @@ function detectRejection(
|
|
|
142
142
|
? args.hub.getActorPrincipalIdForClient(args.targetClientId)
|
|
143
143
|
: (args.targetActorPrincipalId ??
|
|
144
144
|
(isHttpAuthDisabled() && targetClientId
|
|
145
|
-
? args.hubForMissingTarget?.getActorPrincipalIdForClient(
|
|
145
|
+
? args.hubForMissingTarget?.getActorPrincipalIdForClient(
|
|
146
|
+
targetClientId,
|
|
147
|
+
)
|
|
146
148
|
: undefined));
|
|
147
149
|
|
|
148
150
|
let reason: RejectionReason | undefined;
|
|
@@ -262,43 +264,6 @@ export function pickSameUserAutoResolve(args: {
|
|
|
262
264
|
return { kind: "ambiguous" };
|
|
263
265
|
}
|
|
264
266
|
|
|
265
|
-
/**
|
|
266
|
-
* Pick the most recently active capable client owned by the turn actor.
|
|
267
|
-
* `listClientsByCapability` is ordered by recent activity, so the first
|
|
268
|
-
* same-user match provides deterministic routing without broadcasting a host
|
|
269
|
-
* request across multiple devices.
|
|
270
|
-
*/
|
|
271
|
-
export function pickMostRecentSameUserClient(args: {
|
|
272
|
-
hub: Pick<AssistantEventHub, "listClientsByCapability">;
|
|
273
|
-
capability: HostProxyCapability;
|
|
274
|
-
sourceActorPrincipalId: string | undefined;
|
|
275
|
-
}): string | undefined {
|
|
276
|
-
const { hub, capability, sourceActorPrincipalId } = args;
|
|
277
|
-
if (sourceActorPrincipalId == null) {
|
|
278
|
-
return undefined;
|
|
279
|
-
}
|
|
280
|
-
return hub
|
|
281
|
-
.listClientsByCapability(capability)
|
|
282
|
-
.find((client) => client.actorPrincipalId === sourceActorPrincipalId)
|
|
283
|
-
?.clientId;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Error result for an automatic host route with no capable client owned by the
|
|
288
|
-
* actor that initiated the turn.
|
|
289
|
-
*/
|
|
290
|
-
export function unavailableSameUserClientError(
|
|
291
|
-
capability: HostProxyCapability,
|
|
292
|
-
): {
|
|
293
|
-
content: string;
|
|
294
|
-
isError: true;
|
|
295
|
-
} {
|
|
296
|
-
return {
|
|
297
|
-
content: `No connected ${capability} client belongs to this user. Connect a capable client signed in as the same user, then retry.`,
|
|
298
|
-
isError: true,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
267
|
/**
|
|
303
268
|
* Actor principal persisted on a host-proxy pending interaction.
|
|
304
269
|
*
|