@vellumai/assistant 0.8.4 → 0.8.5
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/ARCHITECTURE.md +2 -2
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/openapi.yaml +809 -11
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +34 -37
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
- package/src/__tests__/conversation-agent-loop.test.ts +163 -122
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +178 -15
- package/src/__tests__/conversation-lifecycle.test.ts +52 -11
- package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +77 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +46 -0
- package/src/__tests__/openai-responses-provider.test.ts +114 -12
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +145 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +9 -62
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +6 -5
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/loop.ts +8 -0
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +176 -1
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +7 -6
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/llm.ts +12 -1
- package/src/config/schemas/memory-v2.ts +246 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +52 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
- package/src/daemon/conversation-agent-loop.ts +126 -76
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-runtime-assembly.ts +10 -9
- package/src/daemon/conversation-tool-setup.ts +63 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +14 -29
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +23 -20
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-types/conversations.ts +6 -9
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +6 -14
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +0 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +71 -70
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +10 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +55 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +15 -6
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +17 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/emit-signal.ts +29 -49
- package/src/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +18 -11
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +50 -185
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +32 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +43 -0
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +6 -3
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +78 -21
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +36 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +0 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +142 -36
- package/src/runtime/routes/conversation-routes.ts +252 -410
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +5 -4
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-tool.ts +59 -0
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/web-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +25 -32
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +27 -98
- package/src/tools/ui-surface/definitions.ts +6 -22
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type * as genai from "@google/genai";
|
|
2
|
-
import { ApiError, GoogleGenAI } from "@google/genai";
|
|
2
|
+
import { ApiError, GoogleGenAI, ThinkingLevel } from "@google/genai";
|
|
3
3
|
|
|
4
|
-
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/cache-boundary.js";
|
|
5
4
|
import { isAbortReason } from "../../util/abort-reasons.js";
|
|
6
5
|
import { ProviderError } from "../../util/errors.js";
|
|
7
6
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -34,6 +33,47 @@ function isGemini3Model(model: string): boolean {
|
|
|
34
33
|
return model.startsWith("gemini-3") || model.startsWith("models/gemini-3");
|
|
35
34
|
}
|
|
36
35
|
|
|
36
|
+
const THINKING_LEVEL_BY_NAME: Record<string, ThinkingLevel> = {
|
|
37
|
+
minimal: ThinkingLevel.MINIMAL,
|
|
38
|
+
low: ThinkingLevel.LOW,
|
|
39
|
+
medium: ThinkingLevel.MEDIUM,
|
|
40
|
+
high: ThinkingLevel.HIGH,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Translate the resolved wire-shape `thinking` config into Gemini's
|
|
45
|
+
* `thinkingConfig`. Returns `undefined` when no thinking config was supplied,
|
|
46
|
+
* which lets Google's per-model default apply (e.g. `gemini-3.5-flash`
|
|
47
|
+
* defaults to dynamic medium-level thinking).
|
|
48
|
+
*
|
|
49
|
+
* `enabled: false` maps to `thinkingLevel: MINIMAL` because Gemini 3.x cannot
|
|
50
|
+
* fully disable thinking — `"minimal"` is the floor. `includeThoughts` is
|
|
51
|
+
* gated on `streamThinking` so callers that opted out of streaming thoughts
|
|
52
|
+
* don't pay for thought tokens in the response.
|
|
53
|
+
*/
|
|
54
|
+
function buildThinkingConfig(
|
|
55
|
+
thinking: Record<string, unknown> | undefined,
|
|
56
|
+
): genai.ThinkingConfig | undefined {
|
|
57
|
+
if (!thinking) return undefined;
|
|
58
|
+
if (thinking.type === "disabled") {
|
|
59
|
+
return {
|
|
60
|
+
thinkingLevel: ThinkingLevel.MINIMAL,
|
|
61
|
+
includeThoughts: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (thinking.type !== "adaptive") return undefined;
|
|
65
|
+
|
|
66
|
+
const result: genai.ThinkingConfig = {};
|
|
67
|
+
if (typeof thinking.level === "string") {
|
|
68
|
+
const mapped = THINKING_LEVEL_BY_NAME[thinking.level];
|
|
69
|
+
if (mapped) result.thinkingLevel = mapped;
|
|
70
|
+
}
|
|
71
|
+
if (typeof thinking.streamThinking === "boolean") {
|
|
72
|
+
result.includeThoughts = thinking.streamThinking;
|
|
73
|
+
}
|
|
74
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
37
77
|
function stripGeminiHttpOptions(
|
|
38
78
|
config: genai.GenerateContentConfig,
|
|
39
79
|
): genai.GenerateContentConfig {
|
|
@@ -175,6 +215,9 @@ export class GeminiProvider implements Provider {
|
|
|
175
215
|
const usageAttributionHeaders = configObj?.usageAttributionHeaders as
|
|
176
216
|
| Record<string, string>
|
|
177
217
|
| undefined;
|
|
218
|
+
const thinkingConfig = buildThinkingConfig(
|
|
219
|
+
configObj?.thinking as Record<string, unknown> | undefined,
|
|
220
|
+
);
|
|
178
221
|
const activeModel = modelOverride ?? this.model;
|
|
179
222
|
|
|
180
223
|
try {
|
|
@@ -183,14 +226,14 @@ export class GeminiProvider implements Provider {
|
|
|
183
226
|
const geminiConfig: genai.GenerateContentConfig = {};
|
|
184
227
|
|
|
185
228
|
if (systemPrompt) {
|
|
186
|
-
geminiConfig.systemInstruction = systemPrompt
|
|
187
|
-
SYSTEM_PROMPT_CACHE_BOUNDARY,
|
|
188
|
-
"\n",
|
|
189
|
-
);
|
|
229
|
+
geminiConfig.systemInstruction = systemPrompt;
|
|
190
230
|
}
|
|
191
231
|
if (maxTokens) {
|
|
192
232
|
geminiConfig.maxOutputTokens = maxTokens;
|
|
193
233
|
}
|
|
234
|
+
if (thinkingConfig) {
|
|
235
|
+
geminiConfig.thinkingConfig = thinkingConfig;
|
|
236
|
+
}
|
|
194
237
|
if (tools && tools.length > 0) {
|
|
195
238
|
geminiConfig.tools = [
|
|
196
239
|
{
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import { AnthropicProvider } from "../anthropic/client.js";
|
|
22
22
|
import { FireworksProvider } from "../fireworks/client.js";
|
|
23
23
|
import { GeminiProvider } from "../gemini/client.js";
|
|
24
|
+
import { MinimaxProvider } from "../minimax/client.js";
|
|
24
25
|
import { PROVIDER_CATALOG } from "../model-catalog.js";
|
|
25
26
|
import { OllamaProvider } from "../ollama/client.js";
|
|
26
27
|
import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provider.js";
|
|
@@ -111,6 +112,8 @@ const ADAPTER_FACTORIES: Record<string, AdapterFactory> = {
|
|
|
111
112
|
streamTimeoutMs,
|
|
112
113
|
...(baseURL ? { baseURL } : {}),
|
|
113
114
|
}),
|
|
115
|
+
minimax: ({ apiKey, model, streamTimeoutMs }) =>
|
|
116
|
+
new MinimaxProvider(apiKey, model, { streamTimeoutMs }),
|
|
114
117
|
};
|
|
115
118
|
|
|
116
119
|
/**
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
|
|
3
|
+
import { getLogger } from "../../util/logger.js";
|
|
4
|
+
import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provider.js";
|
|
5
|
+
|
|
6
|
+
const log = getLogger("minimax-client");
|
|
7
|
+
|
|
8
|
+
/** Validation-specific timeout (10s) so a stalled network doesn't block key submission. */
|
|
9
|
+
const VALIDATION_TIMEOUT_MS = 10_000;
|
|
10
|
+
|
|
11
|
+
export interface MinimaxProviderOptions {
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
baseURL?: string;
|
|
14
|
+
streamTimeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const DEFAULT_MINIMAX_BASE_URL = "https://api.minimax.io/v1";
|
|
18
|
+
const FALLBACK_MINIMAX_BASE_URL = "https://api.minimaxi.com/v1";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validate a MiniMax API key by testing against the default URL first,
|
|
22
|
+
* then the fallback URL if the default fails. Both URLs must fail with
|
|
23
|
+
* definitive errors (401/403) for the key to be rejected. Transient errors
|
|
24
|
+
* (429, 5xx, network) allow the key to be stored.
|
|
25
|
+
*/
|
|
26
|
+
export async function validateMinimaxApiKey(
|
|
27
|
+
apiKey: string,
|
|
28
|
+
): Promise<{ valid: true } | { valid: false; reason: string }> {
|
|
29
|
+
// Try default URL first
|
|
30
|
+
const defaultResult = await tryValidate(apiKey, DEFAULT_MINIMAX_BASE_URL);
|
|
31
|
+
if (defaultResult.valid && !defaultResult.transient) {
|
|
32
|
+
return { valid: true };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Default failed or was transient — try fallback URL
|
|
36
|
+
const fallbackResult = await tryValidate(apiKey, FALLBACK_MINIMAX_BASE_URL);
|
|
37
|
+
if (fallbackResult.valid) {
|
|
38
|
+
return { valid: true };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Both URLs failed definitively — reject the key
|
|
42
|
+
return { valid: false, reason: fallbackResult.reason };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function tryValidate(
|
|
46
|
+
apiKey: string,
|
|
47
|
+
baseURL: string,
|
|
48
|
+
): Promise<
|
|
49
|
+
| { valid: true; transient: false }
|
|
50
|
+
| { valid: true; transient: true }
|
|
51
|
+
| { valid: false; reason: string }
|
|
52
|
+
> {
|
|
53
|
+
try {
|
|
54
|
+
const client = new OpenAI({
|
|
55
|
+
apiKey,
|
|
56
|
+
baseURL,
|
|
57
|
+
timeout: VALIDATION_TIMEOUT_MS,
|
|
58
|
+
maxRetries: 0,
|
|
59
|
+
});
|
|
60
|
+
await client.models.list();
|
|
61
|
+
return { valid: true, transient: false };
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error instanceof OpenAI.APIError) {
|
|
64
|
+
if (error.status === 401) {
|
|
65
|
+
return { valid: false, reason: "API key is invalid or expired." };
|
|
66
|
+
}
|
|
67
|
+
if (error.status === 403) {
|
|
68
|
+
return {
|
|
69
|
+
valid: false,
|
|
70
|
+
reason: `MiniMax API error (${error.status}): ${error.message}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Transient errors (429, 5xx, etc.) — try the other URL
|
|
74
|
+
log.warn(
|
|
75
|
+
{ status: error.status, baseURL },
|
|
76
|
+
"MiniMax API returned a transient error during key validation — trying fallback",
|
|
77
|
+
);
|
|
78
|
+
return { valid: true, transient: true };
|
|
79
|
+
}
|
|
80
|
+
// Network errors — try the other URL
|
|
81
|
+
log.warn(
|
|
82
|
+
{
|
|
83
|
+
error: error instanceof Error ? error.message : String(error),
|
|
84
|
+
baseURL,
|
|
85
|
+
},
|
|
86
|
+
"Network error during MiniMax key validation — trying fallback",
|
|
87
|
+
);
|
|
88
|
+
return { valid: true, transient: true };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class MinimaxProvider extends OpenAIChatCompletionsProvider {
|
|
93
|
+
constructor(
|
|
94
|
+
apiKey: string,
|
|
95
|
+
model: string,
|
|
96
|
+
options: MinimaxProviderOptions = {},
|
|
97
|
+
) {
|
|
98
|
+
const baseURL = options.baseURL?.trim() || DEFAULT_MINIMAX_BASE_URL;
|
|
99
|
+
super(apiKey, model, {
|
|
100
|
+
baseURL,
|
|
101
|
+
providerName: "minimax",
|
|
102
|
+
providerLabel: "MiniMax",
|
|
103
|
+
streamTimeoutMs: options.streamTimeoutMs,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -493,6 +493,21 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
493
493
|
cacheReadPer1mTokens: 0.025,
|
|
494
494
|
},
|
|
495
495
|
},
|
|
496
|
+
{
|
|
497
|
+
id: "gemini-3.1-flash-lite",
|
|
498
|
+
displayName: "Gemini 3.1 Flash-Lite",
|
|
499
|
+
contextWindowTokens: 1048576,
|
|
500
|
+
maxOutputTokens: 65536,
|
|
501
|
+
supportsThinking: true,
|
|
502
|
+
supportsCaching: true,
|
|
503
|
+
supportsVision: true,
|
|
504
|
+
supportsToolUse: true,
|
|
505
|
+
pricing: {
|
|
506
|
+
inputPer1mTokens: 0.25,
|
|
507
|
+
outputPer1mTokens: 1.5,
|
|
508
|
+
cacheReadPer1mTokens: 0.025,
|
|
509
|
+
},
|
|
510
|
+
},
|
|
496
511
|
{
|
|
497
512
|
id: "gemini-2.5-flash",
|
|
498
513
|
displayName: "Gemini 2.5 Flash",
|
|
@@ -1122,6 +1137,34 @@ const RAW_PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
1122
1137
|
models: [],
|
|
1123
1138
|
defaultModel: "",
|
|
1124
1139
|
},
|
|
1140
|
+
{
|
|
1141
|
+
id: "minimax",
|
|
1142
|
+
displayName: "MiniMax",
|
|
1143
|
+
subtitle: "MiniMax AI models. Requires a MiniMax API key.",
|
|
1144
|
+
setupMode: "api-key",
|
|
1145
|
+
setupHint: "Enter your MiniMax API key to enable MiniMax models.",
|
|
1146
|
+
envVar: "MINIMAX_API_KEY",
|
|
1147
|
+
credentialsGuide: {
|
|
1148
|
+
description: "Sign in to the MiniMax dashboard and create an API key.",
|
|
1149
|
+
url: "https://platform.minimax.io/",
|
|
1150
|
+
linkLabel: "Open MiniMax Dashboard",
|
|
1151
|
+
},
|
|
1152
|
+
models: [
|
|
1153
|
+
{
|
|
1154
|
+
id: "MiniMax-M2.7",
|
|
1155
|
+
displayName: "MiniMax M2.7",
|
|
1156
|
+
contextWindowTokens: 200000,
|
|
1157
|
+
maxOutputTokens: 16384,
|
|
1158
|
+
supportsThinking: true,
|
|
1159
|
+
supportsCaching: true,
|
|
1160
|
+
supportsVision: false,
|
|
1161
|
+
supportsToolUse: true,
|
|
1162
|
+
},
|
|
1163
|
+
],
|
|
1164
|
+
defaultModel: "MiniMax-M2.7",
|
|
1165
|
+
apiKeyUrl: "https://platform.minimax.io/",
|
|
1166
|
+
apiKeyPlaceholder: "sk-cp-...",
|
|
1167
|
+
},
|
|
1125
1168
|
];
|
|
1126
1169
|
|
|
1127
1170
|
export const PROVIDER_CATALOG: ProviderCatalogEntry[] =
|
|
@@ -24,7 +24,7 @@ const PROVIDER_MODEL_INTENTS: Record<string, Record<ModelIntent, string>> = {
|
|
|
24
24
|
},
|
|
25
25
|
gemini: {
|
|
26
26
|
balanced: "gemini-3-flash-preview",
|
|
27
|
-
"latency-optimized": "gemini-3.1-flash-lite
|
|
27
|
+
"latency-optimized": "gemini-3.1-flash-lite",
|
|
28
28
|
"quality-optimized": "gemini-3.1-pro-preview",
|
|
29
29
|
"vision-optimized": "gemini-3-flash-preview",
|
|
30
30
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
2
|
|
|
3
|
-
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/cache-boundary.js";
|
|
4
3
|
import { isAbortReason } from "../../util/abort-reasons.js";
|
|
5
4
|
import { ProviderError } from "../../util/errors.js";
|
|
6
5
|
import { extractRetryAfterMs } from "../../util/retry.js";
|
|
@@ -155,12 +154,16 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
155
154
|
) {
|
|
156
155
|
this.name = options.providerName ?? "openai";
|
|
157
156
|
this.providerLabel = options.providerLabel ?? "OpenAI";
|
|
157
|
+
this.streamTimeoutMs = options.streamTimeoutMs ?? 1_800_000;
|
|
158
|
+
// Keep the SDK deadline behind our provider stream timeout so
|
|
159
|
+
// createStreamTimeout owns the user-facing timeout error.
|
|
160
|
+
const sdkTimeoutMs = this.streamTimeoutMs + 60_000;
|
|
158
161
|
this.client = new OpenAI({
|
|
159
162
|
apiKey,
|
|
160
163
|
baseURL: options.baseURL,
|
|
164
|
+
timeout: sdkTimeoutMs,
|
|
161
165
|
});
|
|
162
166
|
this.model = model;
|
|
163
|
-
this.streamTimeoutMs = options.streamTimeoutMs ?? 1_800_000;
|
|
164
167
|
this.extraCreateParams = options.extraCreateParams ?? {};
|
|
165
168
|
this.maxReasoningEffort = options.maxReasoningEffort ?? "xhigh";
|
|
166
169
|
this.requestHeaders = options.requestHeaders ?? {};
|
|
@@ -593,7 +596,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
593
596
|
if (systemPrompt) {
|
|
594
597
|
result.push({
|
|
595
598
|
role: "system",
|
|
596
|
-
content: systemPrompt
|
|
599
|
+
content: systemPrompt,
|
|
597
600
|
});
|
|
598
601
|
}
|
|
599
602
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model IDs accepted by the ChatGPT Codex subscription endpoint
|
|
3
|
+
* (`https://chatgpt.com/backend-api/codex`).
|
|
4
|
+
*
|
|
5
|
+
* `oauth_subscription` OpenAI connections hard-route every request to that
|
|
6
|
+
* endpoint, which rejects any model outside this set with HTTP 400. The set
|
|
7
|
+
* gates whether such a connection may serve a given model during auto-
|
|
8
|
+
* resolution of an "Any active OpenAI connection" profile.
|
|
9
|
+
*/
|
|
10
|
+
export const CODEX_SUBSCRIPTION_MODEL_IDS: ReadonlySet<string> = new Set([
|
|
11
|
+
"gpt-5.4",
|
|
12
|
+
"gpt-5.3-codex",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
/** True when `model` is accepted by the Codex subscription endpoint. */
|
|
16
|
+
export function isCodexSubscriptionModel(model: string): boolean {
|
|
17
|
+
return CODEX_SUBSCRIPTION_MODEL_IDS.has(model);
|
|
18
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
2
|
|
|
3
|
-
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/cache-boundary.js";
|
|
4
3
|
import { isAbortReason } from "../../util/abort-reasons.js";
|
|
5
4
|
import { ProviderError } from "../../util/errors.js";
|
|
5
|
+
import { getLogger } from "../../util/logger.js";
|
|
6
6
|
import { extractRetryAfterMs } from "../../util/retry.js";
|
|
7
7
|
import { escapeXmlAttr } from "../../util/xml.js";
|
|
8
8
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
@@ -17,6 +17,8 @@ import type {
|
|
|
17
17
|
import { ContextOverflowError } from "../types.js";
|
|
18
18
|
import { detectOpenAICompatibleContextOverflow } from "./chat-completions-provider.js";
|
|
19
19
|
|
|
20
|
+
const log = getLogger("openai-responses");
|
|
21
|
+
|
|
20
22
|
export interface OpenAIResponsesProviderOptions {
|
|
21
23
|
baseURL?: string;
|
|
22
24
|
providerName?: string;
|
|
@@ -24,7 +26,7 @@ export interface OpenAIResponsesProviderOptions {
|
|
|
24
26
|
streamTimeoutMs?: number;
|
|
25
27
|
useNativeWebSearch?: boolean;
|
|
26
28
|
/** When true, target the Codex subscription endpoint and strip fields it
|
|
27
|
-
* rejects (`max_output_tokens`, `
|
|
29
|
+
* rejects (`max_output_tokens`, `reasoning`, `text`, `tools`). */
|
|
28
30
|
codexSubscription?: boolean;
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -107,6 +109,7 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
107
109
|
private streamTimeoutMs: number;
|
|
108
110
|
private useNativeWebSearch: boolean;
|
|
109
111
|
private codexSubscription: boolean;
|
|
112
|
+
private lastCodexErrorBody: string | undefined;
|
|
110
113
|
|
|
111
114
|
constructor(
|
|
112
115
|
apiKey: string,
|
|
@@ -116,14 +119,39 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
116
119
|
this.name = options.providerName ?? "openai";
|
|
117
120
|
this.providerLabel = options.providerLabel ?? "OpenAI";
|
|
118
121
|
this.codexSubscription = options.codexSubscription ?? false;
|
|
122
|
+
this.streamTimeoutMs = options.streamTimeoutMs ?? 1_800_000;
|
|
123
|
+
// Keep the SDK deadline behind our provider stream timeout so
|
|
124
|
+
// createStreamTimeout owns the user-facing timeout error.
|
|
125
|
+
const sdkTimeoutMs = this.streamTimeoutMs + 60_000;
|
|
119
126
|
this.client = new OpenAI({
|
|
120
127
|
apiKey,
|
|
121
128
|
baseURL: this.codexSubscription
|
|
122
129
|
? "https://chatgpt.com/backend-api/codex"
|
|
123
130
|
: options.baseURL,
|
|
131
|
+
timeout: sdkTimeoutMs,
|
|
132
|
+
...(this.codexSubscription
|
|
133
|
+
? {
|
|
134
|
+
fetch: async (url: RequestInfo | URL, init?: RequestInit) => {
|
|
135
|
+
const res = await globalThis.fetch(url, init);
|
|
136
|
+
if (!res.ok) {
|
|
137
|
+
const body = await res.text();
|
|
138
|
+
this.lastCodexErrorBody = body;
|
|
139
|
+
log.warn(
|
|
140
|
+
{ status: res.status, body, url: String(url) },
|
|
141
|
+
"Codex endpoint raw error response",
|
|
142
|
+
);
|
|
143
|
+
return new Response(body, {
|
|
144
|
+
status: res.status,
|
|
145
|
+
statusText: res.statusText,
|
|
146
|
+
headers: res.headers,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return res;
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
: {}),
|
|
124
153
|
});
|
|
125
154
|
this.model = model;
|
|
126
|
-
this.streamTimeoutMs = options.streamTimeoutMs ?? 1_800_000;
|
|
127
155
|
this.useNativeWebSearch = options.useNativeWebSearch ?? false;
|
|
128
156
|
}
|
|
129
157
|
|
|
@@ -149,35 +177,35 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
149
177
|
const params: Record<string, unknown> = {
|
|
150
178
|
model: modelOverride ?? this.model,
|
|
151
179
|
input,
|
|
180
|
+
...(this.codexSubscription ? { store: false } : {}),
|
|
152
181
|
};
|
|
153
182
|
|
|
154
183
|
if (systemPrompt) {
|
|
155
|
-
params.instructions = systemPrompt
|
|
156
|
-
SYSTEM_PROMPT_CACHE_BOUNDARY,
|
|
157
|
-
"\n",
|
|
158
|
-
);
|
|
184
|
+
params.instructions = systemPrompt;
|
|
159
185
|
}
|
|
160
186
|
|
|
161
187
|
if (maxTokens && !this.codexSubscription) {
|
|
162
188
|
params.max_output_tokens = maxTokens;
|
|
163
189
|
}
|
|
164
190
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
191
|
+
if (!this.codexSubscription) {
|
|
192
|
+
const reasoningEffort = effort
|
|
193
|
+
? EFFORT_TO_REASONING_EFFORT[effort]
|
|
194
|
+
: undefined;
|
|
195
|
+
if (reasoningEffort) {
|
|
196
|
+
params.reasoning = { effort: reasoningEffort };
|
|
197
|
+
}
|
|
171
198
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
199
|
+
if (
|
|
200
|
+
verbosity &&
|
|
201
|
+
VALID_VERBOSITIES.has(verbosity) &&
|
|
202
|
+
modelSupportsVerbosity(modelOverride ?? this.model)
|
|
203
|
+
) {
|
|
204
|
+
params.text = { verbosity };
|
|
205
|
+
}
|
|
178
206
|
}
|
|
179
207
|
|
|
180
|
-
if (tools && tools.length > 0) {
|
|
208
|
+
if (tools && tools.length > 0 && !this.codexSubscription) {
|
|
181
209
|
if (
|
|
182
210
|
this.useNativeWebSearch &&
|
|
183
211
|
tools.some((t) => t.name === "web_search")
|
|
@@ -410,6 +438,21 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
410
438
|
? signal.reason
|
|
411
439
|
: undefined;
|
|
412
440
|
if (error instanceof OpenAI.APIError) {
|
|
441
|
+
// Temporary diagnostic: log the raw error shape for Codex 400 debugging
|
|
442
|
+
if (this.codexSubscription) {
|
|
443
|
+
log.warn(
|
|
444
|
+
{
|
|
445
|
+
status: error.status,
|
|
446
|
+
message: error.message,
|
|
447
|
+
code: error.code,
|
|
448
|
+
type: error.type,
|
|
449
|
+
param: error.param,
|
|
450
|
+
errorBody: error.error,
|
|
451
|
+
headers: Object.fromEntries(error.headers?.entries?.() ?? []),
|
|
452
|
+
},
|
|
453
|
+
"Codex subscription API error — raw details",
|
|
454
|
+
);
|
|
455
|
+
}
|
|
413
456
|
const overflow = detectOpenAICompatibleContextOverflow(error);
|
|
414
457
|
if (overflow) {
|
|
415
458
|
throw new ContextOverflowError(
|
|
@@ -431,8 +474,22 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
431
474
|
if (retryAfterMs !== undefined)
|
|
432
475
|
errorOptions.retryAfterMs = retryAfterMs;
|
|
433
476
|
if (abortReason) errorOptions.abortReason = abortReason;
|
|
477
|
+
let errorDetail = error.message;
|
|
478
|
+
if (this.lastCodexErrorBody) {
|
|
479
|
+
try {
|
|
480
|
+
const parsed = JSON.parse(this.lastCodexErrorBody);
|
|
481
|
+
if (parsed.detail) errorDetail = parsed.detail;
|
|
482
|
+
} catch {
|
|
483
|
+
errorDetail = this.lastCodexErrorBody.slice(0, 200);
|
|
484
|
+
}
|
|
485
|
+
this.lastCodexErrorBody = undefined;
|
|
486
|
+
}
|
|
487
|
+
const extras = [error.code, error.type, error.param]
|
|
488
|
+
.filter(Boolean)
|
|
489
|
+
.join(", ");
|
|
490
|
+
const extraSuffix = extras ? ` [${extras}]` : "";
|
|
434
491
|
throw new ProviderError(
|
|
435
|
-
`${this.providerLabel} API error (${error.status}): ${
|
|
492
|
+
`${this.providerLabel} API error (${error.status}): ${errorDetail}${extraSuffix}`,
|
|
436
493
|
this.name,
|
|
437
494
|
error.status,
|
|
438
495
|
Object.keys(errorOptions).length > 0 ? errorOptions : undefined,
|
|
@@ -9,6 +9,7 @@ import { getConfig } from "../config/loader.js";
|
|
|
9
9
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
10
10
|
import { getDb } from "../memory/db-connection.js";
|
|
11
11
|
import { getLogger } from "../util/logger.js";
|
|
12
|
+
import { isConnectionCompatibleWithModel } from "./connection-model-compat.js";
|
|
12
13
|
import { tryResolveProviderForConnectionName } from "./connection-resolution.js";
|
|
13
14
|
import { listConnections } from "./inference/connections.js";
|
|
14
15
|
import { initializeProviders, listProviders } from "./registry.js";
|
|
@@ -126,7 +127,11 @@ export async function resolveConfiguredProvider(
|
|
|
126
127
|
const candidates = listConnections(getDb(), {
|
|
127
128
|
provider: inferenceProvider,
|
|
128
129
|
});
|
|
129
|
-
const active = candidates.find(
|
|
130
|
+
const active = candidates.find(
|
|
131
|
+
(c) =>
|
|
132
|
+
c.status === "active" &&
|
|
133
|
+
isConnectionCompatibleWithModel(c, resolved.model),
|
|
134
|
+
);
|
|
130
135
|
if (active) {
|
|
131
136
|
connectionName = active.name;
|
|
132
137
|
}
|
|
@@ -147,6 +152,7 @@ export async function resolveConfiguredProvider(
|
|
|
147
152
|
connectionName,
|
|
148
153
|
config,
|
|
149
154
|
inferenceProvider,
|
|
155
|
+
resolved.model,
|
|
150
156
|
);
|
|
151
157
|
if (!connectionProvider) {
|
|
152
158
|
// Soft credential failure — the connection resolved to no usable
|
package/src/providers/retry.ts
CHANGED
|
@@ -47,9 +47,18 @@ const EFFORT_SUPPORTED_PROVIDERS = new Set([
|
|
|
47
47
|
/**
|
|
48
48
|
* Providers that consume the `thinking` config. Anthropic uses it directly on
|
|
49
49
|
* the wire; OpenRouter either forwards it to its Anthropic-compatible path or
|
|
50
|
-
* translates it into the unified `reasoning` parameter on OpenAI-compat calls
|
|
50
|
+
* translates it into the unified `reasoning` parameter on OpenAI-compat calls;
|
|
51
|
+
* Gemini reads `thinking.level` to populate `thinkingConfig.thinkingLevel`.
|
|
51
52
|
*/
|
|
52
|
-
const THINKING_AWARE_PROVIDERS = new Set(["anthropic", "openrouter"]);
|
|
53
|
+
const THINKING_AWARE_PROVIDERS = new Set(["anthropic", "openrouter", "gemini"]);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Providers that consume Gemini-only thinking extras (`level`,
|
|
57
|
+
* `streamThinking`). For other thinking-aware providers, we scrub these from
|
|
58
|
+
* the normalized wire payload because Anthropic's SDK rejects unknown keys
|
|
59
|
+
* inside the `thinking` object with "Extra inputs are not permitted".
|
|
60
|
+
*/
|
|
61
|
+
const THINKING_EXTRA_FIELDS_AWARE_PROVIDERS = new Set(["gemini"]);
|
|
53
62
|
|
|
54
63
|
/**
|
|
55
64
|
* Providers that consume the `verbosity` config. Currently OpenAI (mapped to
|
|
@@ -289,7 +298,8 @@ function normalizeSendMessageOptions(
|
|
|
289
298
|
}
|
|
290
299
|
|
|
291
300
|
// thinking is Anthropic-specific on the wire; OpenRouter reads it as a
|
|
292
|
-
// signal for its unified reasoning parameter
|
|
301
|
+
// signal for its unified reasoning parameter; Gemini reads `level` from it.
|
|
302
|
+
// Strip it for other providers.
|
|
293
303
|
if (
|
|
294
304
|
!THINKING_AWARE_PROVIDERS.has(providerName) &&
|
|
295
305
|
nextConfig.thinking !== undefined
|
|
@@ -297,6 +307,27 @@ function normalizeSendMessageOptions(
|
|
|
297
307
|
delete nextConfig.thinking;
|
|
298
308
|
}
|
|
299
309
|
|
|
310
|
+
// Strip Gemini-only extras (`level`, `streamThinking`) from the wire
|
|
311
|
+
// `thinking` object for providers that don't read them. Anthropic in
|
|
312
|
+
// particular rejects unknown keys inside `thinking` with "Extra inputs are
|
|
313
|
+
// not permitted"; the OpenRouter Anthropic-compat path hits the same SDK.
|
|
314
|
+
if (
|
|
315
|
+
nextConfig.thinking !== undefined &&
|
|
316
|
+
!THINKING_EXTRA_FIELDS_AWARE_PROVIDERS.has(providerName) &&
|
|
317
|
+
typeof nextConfig.thinking === "object" &&
|
|
318
|
+
nextConfig.thinking !== null
|
|
319
|
+
) {
|
|
320
|
+
const wire = nextConfig.thinking as Record<string, unknown>;
|
|
321
|
+
if (wire.level !== undefined || wire.streamThinking !== undefined) {
|
|
322
|
+
const scrubbed: Record<string, unknown> = {};
|
|
323
|
+
for (const [key, value] of Object.entries(wire)) {
|
|
324
|
+
if (key === "level" || key === "streamThinking") continue;
|
|
325
|
+
scrubbed[key] = value;
|
|
326
|
+
}
|
|
327
|
+
nextConfig.thinking = scrubbed;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
300
331
|
// Anthropic (and OpenRouter fronting Anthropic) rejects requests that
|
|
301
332
|
// combine extended thinking with forced tool use (`tool_choice.type` of
|
|
302
333
|
// `"tool"` or `"any"`). Strip thinking when both are present so the
|
|
@@ -1,20 +1,45 @@
|
|
|
1
|
+
import { THINKING_LEVELS, type ThinkingLevel } from "../config/schemas/llm.js";
|
|
2
|
+
|
|
1
3
|
type ThinkingConfigRecord = Record<string, unknown>;
|
|
2
4
|
|
|
5
|
+
const THINKING_LEVEL_SET: ReadonlySet<string> = new Set(THINKING_LEVELS);
|
|
6
|
+
|
|
3
7
|
function isRecord(value: unknown): value is ThinkingConfigRecord {
|
|
4
8
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
9
|
}
|
|
6
10
|
|
|
11
|
+
function pickGeminiExtras(thinking: ThinkingConfigRecord): {
|
|
12
|
+
level?: ThinkingLevel;
|
|
13
|
+
streamThinking?: boolean;
|
|
14
|
+
} {
|
|
15
|
+
const extras: { level?: ThinkingLevel; streamThinking?: boolean } = {};
|
|
16
|
+
if (
|
|
17
|
+
typeof thinking.level === "string" &&
|
|
18
|
+
THINKING_LEVEL_SET.has(thinking.level)
|
|
19
|
+
) {
|
|
20
|
+
extras.level = thinking.level as ThinkingLevel;
|
|
21
|
+
}
|
|
22
|
+
if (typeof thinking.streamThinking === "boolean") {
|
|
23
|
+
extras.streamThinking = thinking.streamThinking;
|
|
24
|
+
}
|
|
25
|
+
return extras;
|
|
26
|
+
}
|
|
27
|
+
|
|
7
28
|
export function normalizeThinkingConfigForWire(
|
|
8
29
|
thinking: unknown,
|
|
9
30
|
): ThinkingConfigRecord | undefined {
|
|
10
31
|
if (!isRecord(thinking)) return undefined;
|
|
11
32
|
|
|
33
|
+
// Already in wire shape — preserve as-is so re-normalization is idempotent
|
|
34
|
+
// and Gemini-only fields stay attached for the Gemini provider to read.
|
|
12
35
|
if (typeof thinking.type === "string") {
|
|
13
36
|
return thinking;
|
|
14
37
|
}
|
|
15
38
|
|
|
39
|
+
const extras = pickGeminiExtras(thinking);
|
|
40
|
+
|
|
16
41
|
if (thinking.enabled === true) {
|
|
17
|
-
return { type: "adaptive" };
|
|
42
|
+
return { type: "adaptive", ...extras };
|
|
18
43
|
}
|
|
19
44
|
|
|
20
45
|
if (thinking.enabled === false) {
|
|
@@ -2,6 +2,7 @@ import { recordUsageEvent } from "../memory/llm-usage-store.js";
|
|
|
2
2
|
import { resolveUsageAttribution } from "../usage/attribution.js";
|
|
3
3
|
import {
|
|
4
4
|
buildPricingUsageFromResponse,
|
|
5
|
+
extractRawUsage,
|
|
5
6
|
resolveStructuredPricing,
|
|
6
7
|
} from "../usage/pricing.js";
|
|
7
8
|
import { getLogger } from "../util/logger.js";
|
|
@@ -76,6 +77,7 @@ export class UsageTrackingProvider implements Provider {
|
|
|
76
77
|
outputTokens: pricingUsage.outputTokens,
|
|
77
78
|
cacheCreationInputTokens: pricingUsage.cacheCreationInputTokens,
|
|
78
79
|
cacheReadInputTokens: pricingUsage.cacheReadInputTokens,
|
|
80
|
+
rawUsage: extractRawUsage(response.rawResponse),
|
|
79
81
|
conversationId: null,
|
|
80
82
|
runId: null,
|
|
81
83
|
requestId: null,
|
package/src/runtime/AGENTS.md
CHANGED
|
@@ -161,10 +161,10 @@ All `/v1/*` endpoints share a per-client-IP sliding-window rate limiter (`middle
|
|
|
161
161
|
|
|
162
162
|
When the limit is exceeded, the limiter returns 429 and logs a structured warning (module: `rate-limiter`) with the denied endpoint and a breakdown of which endpoints consumed the budget in the current window. This makes it easy to identify whether the cause is rapid conversation switching, polling, or unexpected request volume.
|
|
163
163
|
|
|
164
|
-
Logs
|
|
164
|
+
Logs rotate daily into `$VELLUM_WORKSPACE_DIR/data/logs/assistant-YYYY-MM-DD.log` (or into the directory configured via `logFile.dir`). To watch rate limit events in real time:
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
|
-
tail -f
|
|
167
|
+
tail -f "$VELLUM_WORKSPACE_DIR/data/logs/assistant-$(date -u +%Y-%m-%d).log" | grep rate-limit
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
The provider-level rate limiter (`providers/ratelimit.ts`) also logs warnings (module: `rate-limit`) when request rate or token budget limits are enforced.
|