@vellumai/assistant 0.8.6 → 0.8.7-dev.202606052118.34cd356
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 +4 -4
- package/Dockerfile +21 -4
- package/bun.lock +13 -4
- package/docker-entrypoint.sh +12 -8
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/plugins.md +110 -83
- package/examples/plugins/echo/README.md +13 -12
- package/examples/plugins/echo/register.ts +0 -54
- package/knip.json +1 -0
- package/node_modules/@vellumai/environments/bun.lock +24 -0
- package/node_modules/@vellumai/environments/package.json +18 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +95 -0
- package/node_modules/@vellumai/environments/src/index.ts +11 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +73 -0
- package/node_modules/@vellumai/environments/src/types.ts +70 -0
- package/node_modules/@vellumai/environments/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +3 -4
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +13 -8
- package/openapi.yaml +6964 -539
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +88 -54
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +42 -80
- package/src/__tests__/agent-loop-exit-reason.test.ts +188 -45
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +141 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +19 -32
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +7 -5
- package/src/__tests__/agent-loop-thinking.test.ts +17 -12
- package/src/__tests__/agent-loop.test.ts +238 -422
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +6 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +22 -40
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +296 -57
- package/src/__tests__/app-builder-skill-instructions.test.ts +22 -0
- package/src/__tests__/app-control-flow.test.ts +6 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +4 -11
- package/src/__tests__/approval-routes-http.test.ts +8 -3
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-event.test.ts +15 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/assistant-stream-state.test.ts +645 -0
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/avatar-e2e.test.ts +7 -37
- package/src/__tests__/avatar-generator.test.ts +12 -42
- package/src/__tests__/avatar-identity-sync.test.ts +28 -3
- package/src/__tests__/background-shell-bash.test.ts +3 -7
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +69 -15
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/call-pointer-messages.test.ts +5 -3
- package/src/__tests__/call-site-routing-provider.test.ts +22 -40
- package/src/__tests__/catalog-files.test.ts +1 -0
- package/src/__tests__/channel-approval-routes.test.ts +49 -21
- package/src/__tests__/channel-approvals.test.ts +4 -2
- package/src/__tests__/channel-invite-transport.test.ts +1 -5
- package/src/__tests__/channel-readiness-routes.test.ts +0 -4
- package/src/__tests__/channel-readiness-slack-remote.test.ts +2 -7
- package/src/__tests__/channel-retry-sweep.test.ts +71 -79
- package/src/__tests__/clawhub-files.test.ts +1 -0
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction-events.test.ts +5 -17
- package/src/__tests__/compaction-trail-store.test.ts +1 -79
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/compactor-image-manifest-trust.test.ts +112 -0
- package/src/__tests__/computer-use-tools.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +28 -0
- package/src/__tests__/context-search-agent-runner.test.ts +6 -3
- package/src/__tests__/context-token-estimator.test.ts +34 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +291 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +70 -25
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +9 -7
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -34
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +476 -963
- package/src/__tests__/conversation-agent-loop.test.ts +823 -1321
- package/src/__tests__/conversation-analysis-routes.test.ts +7 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-clear-safety.test.ts +20 -10
- package/src/__tests__/conversation-confirmation-signals.test.ts +15 -45
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +10 -17
- package/src/__tests__/conversation-fork-crud.test.ts +86 -172
- package/src/__tests__/conversation-fork-route.test.ts +16 -14
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -6
- package/src/__tests__/conversation-lifecycle.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +3 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -1
- package/src/__tests__/conversation-message-sync-tags.test.ts +3 -4
- package/src/__tests__/conversation-pairing.test.ts +10 -7
- package/src/__tests__/conversation-pre-run-repair.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -0
- package/src/__tests__/conversation-process-callsite.test.ts +27 -30
- package/src/__tests__/conversation-provider-retry-repair.test.ts +80 -51
- package/src/__tests__/conversation-queue.test.ts +272 -164
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +8 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +317 -313
- package/src/__tests__/conversation-runtime-workspace.test.ts +114 -36
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +42 -31
- package/src/__tests__/conversation-slash-unknown.test.ts +13 -15
- package/src/__tests__/conversation-speed-override.test.ts +8 -22
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +90 -15
- package/src/__tests__/conversation-surfaces-app-control.test.ts +32 -4
- package/src/__tests__/conversation-surfaces-state-update.test.ts +5 -2
- package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -15
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +23 -11
- package/src/__tests__/conversation-unread-route.test.ts +14 -2
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-wipe.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +20 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +114 -23
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +34 -13
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/credential-execution-tools.test.ts +1 -2
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/cross-provider-web-search.test.ts +220 -3
- package/src/__tests__/cu-unified-flow.test.ts +26 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -0
- package/src/__tests__/disk-pressure-guard.test.ts +66 -0
- package/src/__tests__/disk-pressure-routes.test.ts +9 -2
- package/src/__tests__/dm-persistence.test.ts +12 -3
- package/src/__tests__/dynamic-page-surface.test.ts +99 -0
- package/src/__tests__/edit-propagation.test.ts +1 -2
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/filing-service.test.ts +2 -2
- package/src/__tests__/first-greeting.test.ts +55 -14
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/gemini-inline-media.test.ts +78 -0
- package/src/__tests__/gemini-provider.test.ts +351 -28
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +60 -71
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +10 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +3 -1
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +162 -0
- package/src/__tests__/history-repair-observability.test.ts +1 -1
- package/src/__tests__/history-repair.test.ts +2 -1
- package/src/__tests__/host-app-control-proxy.test.ts +2 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-proxy.test.ts +2 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/host-file-edit-tool.test.ts +4 -2
- package/src/__tests__/host-file-proxy.test.ts +31 -0
- package/src/__tests__/host-file-read-tool.test.ts +4 -2
- package/src/__tests__/host-file-write-tool.test.ts +9 -3
- package/src/__tests__/host-proxy-preactivation.test.ts +53 -14
- package/src/__tests__/host-shell-tool.test.ts +9 -4
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +47 -114
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +12 -3
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +214 -0
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-attachments.test.ts +7 -8
- package/src/__tests__/list-messages-hidden-metadata.test.ts +55 -15
- package/src/__tests__/list-messages-page-latest.test.ts +60 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +56 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +42 -86
- package/src/__tests__/llm-resolver.test.ts +23 -47
- package/src/__tests__/llm-usage-store.test.ts +268 -1
- package/src/__tests__/log-export-routes.test.ts +59 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -8
- package/src/__tests__/mcp-auth-routes.test.ts +15 -10
- package/src/__tests__/mcp-health-check.test.ts +18 -13
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/messaging-send-tool.test.ts +8 -4
- package/src/__tests__/migration-export-http.test.ts +12 -12
- package/src/__tests__/migration-import-commit-http.test.ts +8 -8
- package/src/__tests__/migration-import-preflight-http.test.ts +7 -7
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +205 -20
- package/src/__tests__/notification-decision-identity.test.ts +9 -18
- package/src/__tests__/notification-decision-recipient-context.test.ts +3 -6
- package/src/__tests__/oauth-commands-routes.test.ts +1 -1
- package/src/__tests__/onboarding-template-contract.test.ts +12 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +97 -71
- package/src/__tests__/openai-responses-provider.test.ts +21 -77
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -286
- package/src/__tests__/parallel-tool.benchmark.test.ts +24 -36
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +3 -1
- package/src/__tests__/pipeline-runner.test.ts +31 -43
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-bootstrap.test.ts +62 -51
- package/src/__tests__/plugin-registry.test.ts +0 -27
- package/src/__tests__/plugin-route-contribution.test.ts +6 -16
- package/src/__tests__/plugin-skill-contribution.test.ts +7 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +10 -26
- package/src/__tests__/plugin-types.test.ts +8 -173
- package/src/__tests__/prechat-onboarding-contract.test.ts +23 -0
- package/src/__tests__/process-message-background-slack.test.ts +17 -16
- package/src/__tests__/process-message-display-content.test.ts +36 -44
- package/src/__tests__/provider-commit-message-generator.test.ts +19 -14
- package/src/__tests__/provider-error-scenarios.test.ts +7 -6
- package/src/__tests__/provider-platform-proxy-integration.test.ts +3 -8
- package/src/__tests__/provider-send-message-override-profile.test.ts +9 -25
- package/src/__tests__/provider-streaming.benchmark.test.ts +12 -22
- package/src/__tests__/provider-usage-tracking.test.ts +0 -6
- package/src/__tests__/ratelimit.test.ts +9 -4
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/relay-server.test.ts +20 -13
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +5 -8
- package/src/__tests__/retry-thinking-tool-choice.test.ts +10 -13
- package/src/__tests__/retry-verbosity-normalization.test.ts +5 -8
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +390 -0
- package/src/__tests__/schedule-routes.test.ts +683 -12
- package/src/__tests__/schedule-store.test.ts +108 -0
- package/src/__tests__/schedule-tools.test.ts +160 -0
- package/src/__tests__/secret-ingress-http.test.ts +2 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +11 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +11 -9
- package/src/__tests__/secret-response-routing.test.ts +13 -11
- package/src/__tests__/send-endpoint-busy.test.ts +6 -2
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/shell-observability.test.ts +249 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +44 -11
- package/src/__tests__/skill-feature-flags.test.ts +6 -6
- package/src/__tests__/skill-load-feature-flag.test.ts +10 -10
- package/src/__tests__/skills-files-catalog-fallback.test.ts +10 -0
- package/src/__tests__/skillssh-files.test.ts +1 -0
- package/src/__tests__/starter-task-flow.test.ts +6 -6
- package/src/__tests__/strip-memory-injections.test.ts +102 -14
- package/src/__tests__/subagent-call-site-routing.test.ts +3 -3
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +19 -16
- package/src/__tests__/system-prompt.test.ts +74 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +9 -25
- package/src/__tests__/thread-backfill.test.ts +4 -9
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +481 -16
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +1 -1
- package/src/__tests__/tools-audio-read.test.ts +113 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +44 -84
- package/src/__tests__/turn-events-store.test.ts +11 -7
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +8 -6
- package/src/__tests__/voice-session-bridge.test.ts +19 -10
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +143 -31
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +695 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +125 -0
- package/src/acp/auto-install.ts +174 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +52 -11
- package/src/acp/resolve-agent.test.ts +147 -6
- package/src/acp/resolve-agent.ts +81 -7
- package/src/acp/resume-hint.ts +22 -0
- package/src/acp/session-manager.ts +487 -71
- package/src/agent/compaction-circuit.ts +98 -0
- package/src/agent/loop.ts +651 -450
- package/src/api/README.md +19 -17
- package/src/api/constants/tool-execution.ts +21 -0
- package/src/api/events/assistant-activity-state.ts +75 -0
- package/src/api/events/assistant-outbound-attachment.ts +25 -27
- package/src/api/events/assistant-text-delta.ts +6 -8
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/assistant-turn-start.ts +5 -7
- package/src/api/events/avatar-updated.ts +24 -0
- package/src/api/events/compaction-circuit-closed.ts +26 -0
- package/src/api/events/compaction-circuit-open.ts +28 -0
- package/src/api/events/confirmation-request.ts +114 -0
- package/src/api/events/contact-request.ts +33 -0
- package/src/api/events/conversation-error.ts +77 -0
- package/src/api/events/conversation-list-invalidated.ts +38 -0
- package/src/api/events/conversation-title-updated.ts +24 -0
- package/src/api/events/disk-pressure-status-changed.ts +61 -0
- package/src/api/events/document-comment-created.ts +24 -28
- package/src/api/events/document-comment-deleted.ts +6 -8
- package/src/api/events/document-comment-reopened.ts +6 -8
- package/src/api/events/document-comment-resolved.ts +8 -10
- package/src/api/events/document-editor-update.ts +27 -0
- package/src/api/events/error.ts +32 -0
- package/src/api/events/generation-cancelled.ts +4 -6
- package/src/api/events/generation-handoff.ts +13 -15
- package/src/api/events/home-feed-updated.ts +26 -0
- package/src/api/events/identity-changed.ts +32 -0
- package/src/api/events/interaction-resolved.ts +50 -0
- package/src/api/events/message-complete.ts +10 -12
- package/src/api/events/message-dequeued.ts +21 -0
- package/src/api/events/message-queued-deleted.ts +23 -0
- package/src/api/events/message-queued.ts +22 -0
- package/src/api/events/message-request-complete.ts +29 -0
- package/src/api/events/navigate-settings.ts +20 -0
- package/src/api/events/notification-intent.ts +33 -0
- package/src/api/events/open-url.ts +6 -8
- package/src/api/events/question-request.ts +67 -0
- package/src/api/events/relationship-state-updated.ts +4 -6
- package/src/api/events/secret-request.ts +42 -0
- package/src/api/events/subagent-event.ts +79 -0
- package/src/api/events/subagent-spawned.ts +40 -0
- package/src/api/events/subagent-status-changed.ts +65 -0
- package/src/api/events/sync-changed.ts +29 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-result.ts +129 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/tool-use-start.ts +8 -10
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/events/turn-profile-auto-routed.ts +28 -0
- package/src/api/events/ui-surface-complete.ts +30 -0
- package/src/api/events/ui-surface-dismiss.ts +22 -0
- package/src/api/events/ui-surface-show.ts +67 -0
- package/src/api/events/ui-surface-update.ts +26 -0
- package/src/api/events/usage-update.ts +34 -0
- package/src/api/events/user-message-echo.ts +35 -0
- package/src/api/index.ts +389 -0
- package/src/api/requests/dictation.ts +45 -0
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/api/responses/disk-pressure-status.ts +26 -0
- package/src/api/responses/home.ts +217 -0
- package/src/api/responses/llm-context-response.ts +2 -0
- package/src/api/responses/memory-v3-selection-log.ts +50 -0
- package/src/api/responses/subagent-detail.ts +48 -0
- package/src/approvals/guardian-decision-primitive.ts +7 -15
- package/src/approvals/guardian-request-resolvers.ts +7 -10
- package/src/avatar/__tests__/avatar-manifest.test.ts +236 -0
- package/src/avatar/__tests__/avatar-store.test.ts +198 -0
- package/src/avatar/avatar-manifest.ts +195 -0
- package/src/avatar/avatar-store.ts +113 -0
- package/src/avatar/traits-png-sync.ts +8 -2
- package/src/background-wake/next-wake.test.ts +31 -1
- package/src/background-wake/next-wake.ts +5 -1
- package/src/calls/call-conversation-messages.ts +6 -4
- package/src/calls/guardian-action-sweep.ts +6 -4
- package/src/calls/relay-server.ts +12 -8
- package/src/calls/voice-session-bridge.ts +13 -27
- package/src/cli/commands/__tests__/memory-v3.test.ts +245 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/avatar.ts +17 -11
- package/src/cli/commands/conversations.ts +15 -1
- package/src/cli/commands/db/__tests__/repair.test.ts +540 -0
- package/src/cli/commands/db/__tests__/status.test.ts +253 -0
- package/src/cli/commands/db/format.ts +48 -0
- package/src/cli/commands/db/index.ts +29 -0
- package/src/cli/commands/db/repair-step-conversation-backfill.ts +345 -0
- package/src/cli/commands/db/repair-step-integrity.ts +146 -0
- package/src/cli/commands/db/repair-steps.ts +164 -0
- package/src/cli/commands/db/repair.ts +141 -0
- package/src/cli/commands/db/status.ts +366 -0
- package/src/cli/commands/memory-v3.ts +159 -445
- package/src/cli/commands/notifications.ts +112 -60
- package/src/cli/lib/cli-colors.ts +24 -6
- package/src/cli/program.ts +4 -5
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +4 -4
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +24 -13
- package/src/config/bundled-skills/acp/SKILL.md +64 -30
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -387
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +6 -9
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +2 -7
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +68 -12
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -226
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/call-site-catalog.ts +8 -15
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +3 -3
- package/src/config/schemas/memory-lifecycle.ts +24 -0
- package/src/config/schemas/memory-v2.ts +8 -253
- package/src/config/schemas/memory-v3.ts +47 -0
- package/src/config/schemas/memory.ts +6 -1
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/timeouts.ts +3 -1
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +55 -32
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +42 -0
- package/src/context/tool-result-truncation.ts +1 -66
- package/src/context/window-manager.ts +141 -26
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +2 -2
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/__tests__/web-search-status-text.test.ts +10 -6
- package/src/daemon/approval-generators.ts +4 -4
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +7 -1
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +793 -215
- package/src/daemon/conversation-agent-loop.ts +487 -1478
- package/src/daemon/conversation-error.ts +7 -7
- package/src/daemon/conversation-history.ts +27 -10
- package/src/daemon/conversation-launch.ts +4 -8
- package/src/daemon/conversation-lifecycle.ts +13 -42
- package/src/daemon/conversation-messaging.ts +8 -9
- package/src/daemon/conversation-notifiers.ts +7 -5
- package/src/daemon/conversation-process.ts +109 -93
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +209 -382
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +15 -95
- package/src/daemon/conversation-surfaces.ts +277 -73
- package/src/daemon/conversation-tool-setup.ts +5 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +123 -146
- package/src/daemon/daemon-skill-host.ts +2 -6
- package/src/daemon/disk-pressure-guard.ts +35 -29
- package/src/daemon/external-plugins-bootstrap.ts +53 -32
- package/src/daemon/first-greeting.ts +26 -4
- package/src/daemon/guardian-action-generators.ts +2 -2
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +9 -23
- package/src/daemon/handlers/shared.ts +158 -82
- package/src/daemon/handlers/skills.ts +53 -20
- package/src/daemon/host-app-control-proxy.ts +54 -1
- package/src/daemon/host-cu-proxy.ts +46 -22
- package/src/daemon/host-file-proxy.ts +25 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -6
- package/src/daemon/lifecycle.ts +53 -55
- package/src/daemon/message-protocol.ts +2 -3
- package/src/daemon/message-provenance.ts +49 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/contacts.ts +3 -20
- package/src/daemon/message-types/conversations.ts +13 -111
- package/src/daemon/message-types/documents.ts +3 -9
- package/src/daemon/message-types/home.ts +4 -17
- package/src/daemon/message-types/integrations.ts +2 -6
- package/src/daemon/message-types/messages.ts +37 -400
- package/src/daemon/message-types/notifications.ts +2 -32
- package/src/daemon/message-types/settings.ts +3 -8
- package/src/daemon/message-types/skills.ts +4 -0
- package/src/daemon/message-types/surfaces.ts +138 -3
- package/src/daemon/message-types/sync.ts +12 -25
- package/src/daemon/message-types/workspace.ts +3 -11
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +50 -49
- package/src/daemon/server.ts +14 -0
- package/src/daemon/tool-side-effects.ts +10 -7
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +14 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -1
- package/src/heartbeat/heartbeat-run-store.ts +54 -1
- package/src/heartbeat/heartbeat-service.ts +42 -0
- package/src/home/feed-types.ts +36 -221
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/email-ipc.test.ts +0 -9
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/routes/__tests__/route-adapter.test.ts +244 -0
- package/src/ipc/routes/route-adapter.ts +45 -6
- package/src/ipc/skill-routes/__tests__/memory.test.ts +33 -9
- package/src/ipc/skill-routes/__tests__/providers.test.ts +10 -10
- package/src/ipc/skill-routes/__tests__/registries.test.ts +28 -18
- package/src/ipc/skill-routes/memory.ts +29 -14
- package/src/ipc/skill-routes/providers.ts +5 -6
- package/src/ipc/skill-routes/registries.ts +13 -61
- package/src/live-voice/__tests__/live-voice-archive.test.ts +24 -11
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/conversation-queries.test.ts +192 -8
- package/src/memory/__tests__/db-maintenance.test.ts +128 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +5 -4
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +10 -6
- package/src/memory/__tests__/memory-v3-selections-migration.test.ts +103 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/context-search/agent-runner.ts +2 -4
- package/src/memory/conversation-crud.ts +39 -8
- package/src/memory/conversation-queries.ts +78 -22
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +14 -0
- package/src/memory/db-maintenance.ts +18 -2
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/consolidation.ts +8 -11
- package/src/memory/graph/conversation-graph-memory.ts +106 -8
- package/src/memory/graph/extraction.ts +6 -9
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.ts +20 -26
- package/src/memory/graph/tools.ts +4 -4
- package/src/memory/job-handlers/conversation-starters.ts +45 -34
- package/src/memory/job-handlers/summarization.ts +1 -2
- package/src/memory/jobs-store.ts +36 -1
- package/src/memory/jobs-worker.ts +82 -43
- package/src/memory/llm-request-log-source-clickhouse.ts +5 -31
- package/src/memory/llm-request-log-source-local.ts +0 -11
- package/src/memory/llm-request-log-source.ts +9 -25
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +234 -50
- package/src/memory/memory-marker.ts +17 -0
- package/src/memory/memory-retrospective-job.ts +6 -2
- package/src/memory/memory-v2-activation-log-store.ts +1 -83
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/267-llm-usage-events-add-assistant-version.ts +46 -0
- package/src/memory/migrations/268-add-memory-v3-selections.ts +28 -0
- package/src/memory/migrations/269-schedule-script-timeout.ts +11 -0
- package/src/memory/migrations/270-messages-role-created-at-index.ts +18 -0
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/__tests__/267-llm-usage-events-add-assistant-version.test.ts +117 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +27 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +125 -1
- package/src/memory/v2/__tests__/migration.test.ts +11 -3
- package/src/memory/v2/__tests__/page-index.test.ts +37 -1
- package/src/memory/v2/__tests__/router.test.ts +14 -4
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -5
- package/src/memory/v2/backfill-jobs.ts +6 -0
- package/src/memory/v2/consolidation-job.ts +99 -10
- package/src/memory/v2/migration.ts +5 -3
- package/src/memory/v2/page-index.ts +11 -0
- package/src/memory/v2/router.ts +8 -11
- package/src/memory/v2/sweep-job.ts +8 -11
- package/src/memory/v2/types.ts +1 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.ts +2 -2
- package/src/messaging/style-analyzer.ts +8 -11
- package/src/notifications/conversation-pairing.ts +8 -13
- package/src/notifications/decision-engine.ts +16 -16
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/notifications/preference-extractor.ts +11 -14
- package/src/permissions/prompter.ts +46 -36
- package/src/permissions/question-prompter.test.ts +35 -26
- package/src/permissions/question-prompter.ts +6 -10
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +10 -1
- package/src/plugin-api/types.ts +176 -4
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +15 -0
- package/src/plugins/defaults/compaction/register.ts +24 -0
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/package.json +15 -0
- package/src/plugins/defaults/empty-response/register.ts +23 -0
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/history-repair/package.json +15 -0
- package/src/plugins/defaults/history-repair/register.ts +24 -0
- package/src/{daemon/history-repair.ts → plugins/defaults/history-repair/terminal.ts} +48 -35
- package/src/plugins/defaults/index.ts +22 -49
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors.ts → memory-retrieval/injectors.ts} +295 -112
- package/src/plugins/defaults/memory-v3-shadow/__tests__/assign.test.ts +242 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +118 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/core.test.ts +39 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +36 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +37 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/health.test.ts +219 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +330 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +288 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/needle.test.ts +107 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +436 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/reconcile.test.ts +274 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +61 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/router.test.ts +332 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +179 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selector.test.ts +470 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +432 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/snapshot.test.ts +168 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/tree.test.ts +192 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +54 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +106 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +44 -0
- package/src/plugins/defaults/memory-v3-shadow/assign.ts +268 -0
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +124 -0
- package/src/plugins/defaults/memory-v3-shadow/core.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/data/README.md +84 -0
- package/src/plugins/defaults/memory-v3-shadow/data/assignments.json +5 -0
- package/src/plugins/defaults/memory-v3-shadow/data/core.json +1 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-x.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-a/topic-y.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/data/leaves/domain-b/topic-z.md +9 -0
- package/src/plugins/defaults/memory-v3-shadow/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +314 -0
- package/src/plugins/defaults/memory-v3-shadow/needle.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +126 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +15 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +34 -0
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/reconcile.ts +523 -0
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +32 -0
- package/src/plugins/defaults/memory-v3-shadow/router.ts +190 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +84 -0
- package/src/plugins/defaults/memory-v3-shadow/selector.ts +226 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +349 -0
- package/src/plugins/defaults/memory-v3-shadow/snapshot.ts +209 -0
- package/src/plugins/defaults/memory-v3-shadow/tree.ts +174 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +59 -0
- package/src/plugins/defaults/memory-v3-shadow/working-set.ts +88 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +15 -0
- package/src/plugins/defaults/title-generate/register.ts +35 -0
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +15 -0
- package/src/plugins/defaults/tool-error/register.ts +23 -0
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/package.json +15 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +24 -0
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +132 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/pipeline.ts +8 -35
- package/src/plugins/registry.ts +8 -25
- package/src/plugins/types.ts +62 -721
- package/src/plugins/user-loader.ts +4 -3
- package/src/proactive-artifact/aux-message-injector.ts +4 -5
- package/src/proactive-artifact/job.test.ts +28 -21
- package/src/proactive-artifact/job.ts +3 -1
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/sections.ts +20 -7
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +2 -2
- package/src/prompts/templates/BOOTSTRAP.md +7 -3
- package/src/prompts/templates/system-sections.ts +21 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -25
- package/src/providers/__tests__/satellite-connection-routing.test.ts +7 -21
- package/src/providers/anthropic/client.ts +61 -34
- package/src/providers/call-site-routing.ts +1 -9
- package/src/providers/gemini/client.ts +152 -34
- package/src/providers/gemini/inline-media.ts +74 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -2
- package/src/providers/openai/chat-completions-provider.ts +45 -4
- package/src/providers/openai/responses-provider.ts +1 -4
- package/src/providers/openrouter/client.ts +2 -6
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/providers/provider-send-message.ts +6 -6
- package/src/providers/ratelimit.ts +1 -9
- package/src/providers/retry.ts +0 -5
- package/src/providers/types.ts +11 -2
- package/src/providers/usage-tracking.ts +1 -9
- package/src/runtime/__tests__/agent-wake.test.ts +141 -32
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -3
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +95 -23
- package/src/runtime/assistant-event-hub.ts +38 -8
- package/src/runtime/assistant-stream-state.ts +368 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +75 -109
- package/src/runtime/auth/__tests__/route-policy.test.ts +153 -170
- package/src/runtime/auth/route-policy.ts +42 -1079
- package/src/runtime/background-job-runner.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -1
- package/src/runtime/channel-approvals.ts +4 -15
- package/src/runtime/channel-invite-transport.ts +5 -6
- package/src/runtime/channel-readiness-service.ts +2 -5
- package/src/runtime/channel-retry-sweep.ts +12 -16
- package/src/runtime/http-router.ts +35 -43
- package/src/runtime/http-types.ts +23 -71
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/invite-instruction-generator.ts +3 -3
- package/src/runtime/pending-interactions.ts +3 -2
- package/src/runtime/routes/__tests__/acp-routes.test.ts +253 -55
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +565 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +62 -32
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +237 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -22
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +7 -2
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +6 -6
- package/src/runtime/routes/__tests__/stt-routes.test.ts +3 -3
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +5 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +9 -5
- package/src/runtime/routes/acp-routes.test.ts +186 -100
- package/src/runtime/routes/acp-routes.ts +110 -35
- package/src/runtime/routes/app-management-routes.ts +93 -131
- package/src/runtime/routes/app-routes.ts +38 -20
- package/src/runtime/routes/approval-routes.ts +17 -5
- package/src/runtime/routes/attachment-routes.ts +51 -16
- package/src/runtime/routes/audio-routes.ts +1 -0
- package/src/runtime/routes/audit-routes.ts +5 -0
- package/src/runtime/routes/auth-routes.ts +5 -0
- package/src/runtime/routes/avatar-routes.ts +264 -59
- package/src/runtime/routes/background-tool-routes.ts +9 -0
- package/src/runtime/routes/background-wake-routes.ts +13 -3
- package/src/runtime/routes/backup-routes.ts +45 -0
- package/src/runtime/routes/bookmark-routes.ts +13 -0
- package/src/runtime/routes/brain-graph-routes.ts +9 -0
- package/src/runtime/routes/browser-routes.ts +6 -1
- package/src/runtime/routes/browser-tabs-routes.ts +11 -10
- package/src/runtime/routes/btw-routes.ts +34 -24
- package/src/runtime/routes/cache-routes.ts +13 -0
- package/src/runtime/routes/call-routes.ts +21 -10
- package/src/runtime/routes/channel-availability-routes.ts +5 -1
- package/src/runtime/routes/channel-readiness-routes.ts +37 -4
- package/src/runtime/routes/channel-route-definitions.ts +21 -0
- package/src/runtime/routes/channel-verification-routes.ts +21 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +9 -2
- package/src/runtime/routes/client-routes.ts +9 -0
- package/src/runtime/routes/consolidation-routes.ts +133 -25
- package/src/runtime/routes/contact-prompt-routes.ts +9 -0
- package/src/runtime/routes/contact-routes.ts +90 -23
- package/src/runtime/routes/content-source-routes.ts +5 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +5 -1
- package/src/runtime/routes/conversation-attention-routes.ts +5 -0
- package/src/runtime/routes/conversation-cli-routes.ts +54 -7
- package/src/runtime/routes/conversation-compaction-routes.ts +54 -25
- package/src/runtime/routes/conversation-list-routes.ts +81 -12
- package/src/runtime/routes/conversation-management-routes.ts +57 -14
- package/src/runtime/routes/conversation-query-routes.ts +90 -41
- package/src/runtime/routes/conversation-routes.ts +446 -204
- package/src/runtime/routes/conversation-starter-routes.ts +35 -20
- package/src/runtime/routes/conversations-import-routes.ts +30 -8
- package/src/runtime/routes/credential-prompt-routes.ts +5 -0
- package/src/runtime/routes/credential-routes.ts +25 -6
- package/src/runtime/routes/debug-bash-routes.ts +5 -0
- package/src/runtime/routes/debug-routes.ts +11 -2
- package/src/runtime/routes/defer-routes.ts +13 -0
- package/src/runtime/routes/diagnostics-routes.ts +37 -46
- package/src/runtime/routes/disk-pressure-routes.ts +17 -31
- package/src/runtime/routes/document-comments-routes.ts +46 -27
- package/src/runtime/routes/documents-routes.ts +25 -10
- package/src/runtime/routes/domain-routes.ts +98 -51
- package/src/runtime/routes/email-routes.ts +33 -0
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +107 -8
- package/src/runtime/routes/filing-routes.ts +9 -4
- package/src/runtime/routes/gateway-log-routes.ts +31 -4
- package/src/runtime/routes/global-search-routes.ts +53 -50
- package/src/runtime/routes/group-routes.ts +21 -5
- package/src/runtime/routes/guardian-action-routes.ts +9 -0
- package/src/runtime/routes/guardian-approval-interception.ts +0 -31
- package/src/runtime/routes/heartbeat-routes.ts +57 -21
- package/src/runtime/routes/home-feed-routes.ts +23 -19
- package/src/runtime/routes/home-state-routes.ts +8 -40
- package/src/runtime/routes/host-app-control-routes.ts +6 -1
- package/src/runtime/routes/host-bash-routes.ts +5 -0
- package/src/runtime/routes/host-browser-routes.ts +13 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +26 -6
- package/src/runtime/routes/host-transfer-routes.ts +13 -2
- package/src/runtime/routes/http-adapter.ts +1 -2
- package/src/runtime/routes/identity-intro-cache.ts +28 -40
- package/src/runtime/routes/identity-routes.ts +236 -20
- package/src/runtime/routes/image-generation-routes.ts +45 -2
- package/src/runtime/routes/inbound-message-handler.ts +16 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +0 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +15 -19
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +13 -3
- package/src/runtime/routes/inference-provider-connection-routes.ts +21 -5
- package/src/runtime/routes/inference-send-routes.ts +11 -11
- package/src/runtime/routes/integrations/a2a.ts +32 -7
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +23 -3
- package/src/runtime/routes/integrations/slack/share.ts +36 -8
- package/src/runtime/routes/integrations/telegram.ts +34 -9
- package/src/runtime/routes/integrations/twilio.ts +77 -7
- package/src/runtime/routes/integrations/vercel.ts +3 -3
- package/src/runtime/routes/internal-oauth-routes.ts +5 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/internal-twilio-routes.ts +13 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +39 -4
- package/src/runtime/routes/log-export-routes.ts +36 -10
- package/src/runtime/routes/mcp-auth-routes.ts +25 -0
- package/src/runtime/routes/memory-item-routes.ts +21 -10
- package/src/runtime/routes/memory-v2-routes.ts +105 -44
- package/src/runtime/routes/memory-v3-routes.ts +306 -408
- package/src/runtime/routes/migration-rollback-routes.ts +5 -1
- package/src/runtime/routes/migration-routes.ts +29 -0
- package/src/runtime/routes/notification-routes.ts +17 -1
- package/src/runtime/routes/oauth-apps.ts +99 -23
- package/src/runtime/routes/oauth-commands-routes.ts +37 -14
- package/src/runtime/routes/oauth-connect-routes.ts +9 -0
- package/src/runtime/routes/oauth-lifecycle-routes.ts +5 -1
- package/src/runtime/routes/oauth-providers.ts +79 -15
- package/src/runtime/routes/platform-routes.ts +102 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +9 -6
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +37 -16
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +7 -3
- package/src/runtime/routes/playground/__tests__/state.test.ts +10 -3
- package/src/runtime/routes/playground/force-compact.ts +2 -2
- package/src/runtime/routes/playground/helpers.ts +1 -2
- package/src/runtime/routes/playground/inject-failures.ts +13 -8
- package/src/runtime/routes/playground/reset-circuit.ts +14 -9
- package/src/runtime/routes/playground/seed-conversation.ts +1 -1
- package/src/runtime/routes/playground/seeded-conversations.ts +3 -3
- package/src/runtime/routes/playground/state.ts +4 -3
- package/src/runtime/routes/plugins-routes.ts +22 -19
- package/src/runtime/routes/profiler-routes.ts +17 -4
- package/src/runtime/routes/ps-routes.ts +5 -0
- package/src/runtime/routes/publish-routes.ts +13 -3
- package/src/runtime/routes/question-routes.ts +5 -0
- package/src/runtime/routes/recording-routes.ts +25 -12
- package/src/runtime/routes/rename-conversation-routes.ts +10 -0
- package/src/runtime/routes/sanity-routes.ts +9 -2
- package/src/runtime/routes/schedule-routes.ts +288 -88
- package/src/runtime/routes/secret-routes.ts +31 -6
- package/src/runtime/routes/sequence-routes.ts +33 -0
- package/src/runtime/routes/settings-routes.ts +65 -19
- package/src/runtime/routes/skills-routes.ts +166 -73
- package/src/runtime/routes/slack-channel-routes.ts +5 -0
- package/src/runtime/routes/stt-routes.ts +13 -6
- package/src/runtime/routes/subagents-routes.ts +24 -18
- package/src/runtime/routes/suggest-trust-rule-routes.ts +7 -2
- package/src/runtime/routes/surface-action-routes.ts +9 -0
- package/src/runtime/routes/surface-content-routes.ts +10 -2
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/task-routes.ts +37 -0
- package/src/runtime/routes/telemetry-routes.ts +9 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trace-event-routes.ts +42 -1
- package/src/runtime/routes/trust-rules-routes.ts +31 -2
- package/src/runtime/routes/tts-routes.ts +48 -6
- package/src/runtime/routes/types.ts +83 -16
- package/src/runtime/routes/ui-request-routes.ts +5 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +5 -0
- package/src/runtime/routes/usage-routes.ts +118 -42
- package/src/runtime/routes/user-routes-cli.ts +9 -0
- package/src/runtime/routes/user-routes.ts +5 -1
- package/src/runtime/routes/wake-conversation-routes.ts +5 -0
- package/src/runtime/routes/watcher-routes.ts +21 -0
- package/src/runtime/routes/webhook-routes.ts +50 -2
- package/src/runtime/routes/wipe-conversation-routes.ts +5 -0
- package/src/runtime/routes/work-items-routes.ts +49 -23
- package/src/runtime/routes/workspace-commit-routes.ts +5 -0
- package/src/runtime/routes/workspace-routes.test.ts +42 -0
- package/src/runtime/routes/workspace-routes.ts +124 -9
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +8 -4
- package/src/runtime/services/analyze-conversation.ts +5 -8
- package/src/runtime/services/conversation-serializer.ts +24 -2
- package/src/runtime/sync/resource-sync-events.ts +16 -2
- package/src/runtime/sync/sync-publisher.ts +2 -2
- package/src/schedule/run-script.ts +28 -3
- package/src/schedule/schedule-store.ts +28 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +15 -6
- package/src/signals/cancel.ts +2 -4
- package/src/signals/user-message.ts +5 -8
- package/src/skills/catalog-files.ts +4 -1
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -0
- package/src/skills/skillssh-files.ts +1 -0
- package/src/subagent/manager.ts +20 -11
- package/src/telemetry/types.ts +55 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +250 -4
- package/src/telemetry/usage-telemetry-reporter.ts +88 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +198 -93
- package/src/tools/acp/spawn.ts +32 -70
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/definitions.ts +8 -4
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +120 -105
- package/src/tools/ask-question/ask-question-tool.ts +85 -90
- package/src/tools/computer-use/definitions.ts +28 -24
- package/src/tools/credential-execution/make-authenticated-request.ts +56 -51
- package/src/tools/credential-execution/manage-secure-command-tool.ts +2 -2
- package/src/tools/credential-execution/run-authenticated-command.ts +82 -77
- package/src/tools/credentials/vault.ts +112 -111
- package/src/tools/execution-target.ts +1 -1
- package/src/tools/execution-timeout.ts +3 -4
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/edit.ts +45 -42
- package/src/tools/filesystem/list.ts +33 -30
- package/src/tools/filesystem/read.ts +54 -35
- package/src/tools/filesystem/write.ts +69 -32
- package/src/tools/host-filesystem/edit.ts +44 -42
- package/src/tools/host-filesystem/read.ts +49 -35
- package/src/tools/host-filesystem/transfer.ts +121 -108
- package/src/tools/host-filesystem/write.ts +33 -31
- package/src/tools/host-terminal/host-shell.ts +50 -48
- package/src/tools/memory/register.ts +23 -24
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-fetch.ts +49 -46
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +223 -61
- package/src/tools/registry.ts +39 -16
- package/src/tools/schedule/create.ts +13 -0
- package/src/tools/schedule/update.ts +16 -0
- package/src/tools/shared/filesystem/audio-read.ts +122 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/execute.ts +34 -31
- package/src/tools/skills/load.ts +29 -23
- package/src/tools/subagent/notify-parent.ts +35 -32
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/system/avatar-generator.ts +13 -22
- package/src/tools/system/request-permission.ts +30 -27
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/terminal/shell.ts +190 -61
- package/src/tools/tool-defaults.ts +20 -9
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +74 -23
- package/src/tools/ui-surface/definitions.ts +99 -10
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/usage/types.ts +10 -0
- package/src/util/errors.ts +2 -2
- package/src/util/map-limit.ts +27 -0
- package/src/util/mutex.ts +47 -0
- package/src/util/platform.ts +15 -12
- package/src/work-items/work-item-runner.ts +7 -2
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +7 -20
- package/src/workspace/migrations/092-backfill-v3-leaves.ts +169 -0
- package/src/workspace/migrations/093-backfill-leaf-ids.ts +144 -0
- package/src/workspace/migrations/094-seed-avatar-manifest.ts +155 -0
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/__tests__/094-seed-avatar-manifest.test.ts +136 -0
- package/src/workspace/migrations/__tests__/backfill-leaf-ids.test.ts +175 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +124 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/src/workspace/provider-commit-message-generator.ts +15 -17
- package/tsconfig.json +4 -1
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -262
- package/src/__tests__/empty-response-pipeline.test.ts +0 -301
- package/src/__tests__/history-repair-pipeline.test.ts +0 -396
- package/src/__tests__/llm-call-pipeline.test.ts +0 -281
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -514
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -481
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -344
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +0 -340
- package/src/cli/commands/memory-v3-render.ts +0 -491
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/daemon/message-types/disk-pressure.ts +0 -9
- package/src/email/feature-gate.ts +0 -23
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/memory/v3/__tests__/coactivation-store.test.ts +0 -422
- package/src/memory/v3/__tests__/consolidation-job.test.ts +0 -466
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +0 -270
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +0 -324
- package/src/memory/v3/__tests__/edges.test.ts +0 -706
- package/src/memory/v3/__tests__/filter.test.ts +0 -560
- package/src/memory/v3/__tests__/gate.test.ts +0 -637
- package/src/memory/v3/__tests__/index-composition.test.ts +0 -291
- package/src/memory/v3/__tests__/loop.test.ts +0 -775
- package/src/memory/v3/__tests__/retriever.test.ts +0 -226
- package/src/memory/v3/__tests__/scouts.test.ts +0 -489
- package/src/memory/v3/__tests__/shadow-diff.test.ts +0 -225
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +0 -398
- package/src/memory/v3/__tests__/system-prompts.test.ts +0 -154
- package/src/memory/v3/__tests__/traversal.test.ts +0 -508
- package/src/memory/v3/__tests__/tree-index.test.ts +0 -280
- package/src/memory/v3/__tests__/tree-store.test.ts +0 -529
- package/src/memory/v3/__tests__/tree-walk.test.ts +0 -784
- package/src/memory/v3/__tests__/validate.test.ts +0 -277
- package/src/memory/v3/auto-edges.ts +0 -223
- package/src/memory/v3/coactivation-store.ts +0 -124
- package/src/memory/v3/consolidation-job.ts +0 -323
- package/src/memory/v3/coretrieval-seed.ts +0 -240
- package/src/memory/v3/edge-learning-job.ts +0 -160
- package/src/memory/v3/edges.ts +0 -286
- package/src/memory/v3/filter.ts +0 -286
- package/src/memory/v3/gate.ts +0 -349
- package/src/memory/v3/index-composition.ts +0 -126
- package/src/memory/v3/llm-capture.ts +0 -46
- package/src/memory/v3/loop.ts +0 -430
- package/src/memory/v3/maintenance.ts +0 -144
- package/src/memory/v3/prompt-context.ts +0 -33
- package/src/memory/v3/prompts/consolidation.ts +0 -458
- package/src/memory/v3/prompts/system-prompts.ts +0 -196
- package/src/memory/v3/retriever.ts +0 -33
- package/src/memory/v3/scouts.ts +0 -431
- package/src/memory/v3/shadow-diff.ts +0 -287
- package/src/memory/v3/shadow-middleware.ts +0 -347
- package/src/memory/v3/traversal.ts +0 -211
- package/src/memory/v3/tree-index.ts +0 -237
- package/src/memory/v3/tree-store.ts +0 -394
- package/src/memory/v3/tree-walk.ts +0 -356
- package/src/memory/v3/types.ts +0 -65
- package/src/memory/v3/validate.ts +0 -323
- package/src/plugins/defaults/circuit-breaker.ts +0 -141
- package/src/plugins/defaults/compaction.ts +0 -141
- package/src/plugins/defaults/empty-response.ts +0 -124
- package/src/plugins/defaults/history-repair.ts +0 -83
- package/src/plugins/defaults/llm-call.ts +0 -77
- package/src/plugins/defaults/memory-retrieval.ts +0 -219
- package/src/plugins/defaults/overflow-reduce.ts +0 -185
- package/src/plugins/defaults/persistence.ts +0 -146
- package/src/plugins/defaults/title-generate.ts +0 -90
- package/src/plugins/defaults/token-estimate.ts +0 -101
- package/src/plugins/defaults/tool-error.ts +0 -119
- package/src/plugins/defaults/tool-execute.ts +0 -87
- package/src/plugins/defaults/tool-result-truncate.ts +0 -84
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +0 -35
- package/src/skills/category-inference.ts +0 -111
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type * as genai from "@google/genai";
|
|
2
2
|
import { ApiError, GoogleGenAI, ThinkingLevel } from "@google/genai";
|
|
3
3
|
|
|
4
|
+
import {
|
|
5
|
+
THINKING_LEVELS,
|
|
6
|
+
type ThinkingLevel as ThinkingLevelName,
|
|
7
|
+
} from "../../config/schemas/llm.js";
|
|
4
8
|
import { isAbortReason } from "../../util/abort-reasons.js";
|
|
5
9
|
import { ProviderError } from "../../util/errors.js";
|
|
6
10
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -12,12 +16,16 @@ import type {
|
|
|
12
16
|
Provider,
|
|
13
17
|
ProviderResponse,
|
|
14
18
|
SendMessageOptions,
|
|
15
|
-
ToolDefinition,
|
|
16
19
|
} from "../types.js";
|
|
17
20
|
import {
|
|
18
21
|
ContextOverflowError,
|
|
19
22
|
extractOverflowTokensFromMessage,
|
|
20
23
|
} from "../types.js";
|
|
24
|
+
import {
|
|
25
|
+
base64ByteLength,
|
|
26
|
+
GEMINI_MAX_INLINE_AUDIO_BYTES,
|
|
27
|
+
normalizeGeminiAudioMime,
|
|
28
|
+
} from "./inline-media.js";
|
|
21
29
|
|
|
22
30
|
/**
|
|
23
31
|
* Token/context-specific phrases that reliably indicate context-overflow
|
|
@@ -34,40 +42,100 @@ function isGemini3Model(model: string): boolean {
|
|
|
34
42
|
return model.startsWith("gemini-3") || model.startsWith("models/gemini-3");
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
const THINKING_LEVEL_BY_NAME: Record<
|
|
45
|
+
const THINKING_LEVEL_BY_NAME: Record<ThinkingLevelName, ThinkingLevel> = {
|
|
38
46
|
minimal: ThinkingLevel.MINIMAL,
|
|
39
47
|
low: ThinkingLevel.LOW,
|
|
40
48
|
medium: ThinkingLevel.MEDIUM,
|
|
41
49
|
high: ThinkingLevel.HIGH,
|
|
42
50
|
};
|
|
43
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Default thinking level for Gemini Pro models when the profile doesn't pin
|
|
54
|
+
* one. Pro rejects `"minimal"` and an absent level resolves to `"minimal"`
|
|
55
|
+
* upstream, so we pin Google's documented Pro default (`"high"`) — always a
|
|
56
|
+
* supported value.
|
|
57
|
+
*/
|
|
58
|
+
const GEMINI_PRO_DEFAULT_THINKING_LEVEL: ThinkingLevelName = "high";
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gemini 3.x Pro family accepts only `low`/`medium`/`high` (no `"minimal"`) and
|
|
62
|
+
* cannot fully disable thinking. Matches `gemini-3.1-pro-preview`,
|
|
63
|
+
* `gemini-3.1-pro-preview-customtools`, and future `gemini-3*pro*`.
|
|
64
|
+
*/
|
|
65
|
+
function isGeminiProModel(model: string): boolean {
|
|
66
|
+
const normalized = model.startsWith("models/")
|
|
67
|
+
? model.slice("models/".length)
|
|
68
|
+
: model;
|
|
69
|
+
return /^gemini-3.*pro/.test(normalized);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Lowest thinking level the model accepts. Pro's floor is `"low"`; every other
|
|
74
|
+
* thinking-capable Gemini model accepts `"minimal"`.
|
|
75
|
+
*/
|
|
76
|
+
function geminiThinkingFloor(model: string): ThinkingLevelName {
|
|
77
|
+
return isGeminiProModel(model) ? "low" : "minimal";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Raise `level` to `floor` when it sits below it, so we never send a level the
|
|
82
|
+
* model rejects (e.g. `"minimal"` to a Pro model).
|
|
83
|
+
*/
|
|
84
|
+
function clampThinkingLevelToFloor(
|
|
85
|
+
level: ThinkingLevelName,
|
|
86
|
+
floor: ThinkingLevelName,
|
|
87
|
+
): ThinkingLevelName {
|
|
88
|
+
return THINKING_LEVELS.indexOf(level) < THINKING_LEVELS.indexOf(floor)
|
|
89
|
+
? floor
|
|
90
|
+
: level;
|
|
91
|
+
}
|
|
92
|
+
|
|
44
93
|
/**
|
|
45
94
|
* Translate the resolved wire-shape `thinking` config into Gemini's
|
|
46
|
-
* `thinkingConfig
|
|
47
|
-
*
|
|
48
|
-
*
|
|
95
|
+
* `thinkingConfig`, guaranteeing the emitted `thinkingLevel` is one the model
|
|
96
|
+
* accepts. Returns `undefined` when nothing needs to be set, which lets
|
|
97
|
+
* Google's per-model default apply (e.g. `gemini-3.5-flash` defaults to
|
|
98
|
+
* dynamic medium-level thinking).
|
|
99
|
+
*
|
|
100
|
+
* - `enabled: false` maps to the model's floor — the most "off" state it
|
|
101
|
+
* allows (`"minimal"` for most models, `"low"` for Pro, which can't disable
|
|
102
|
+
* thinking).
|
|
103
|
+
* - An explicit `level` below the floor is raised to the floor.
|
|
104
|
+
* - When no `level` is pinned, Pro models get the documented default (`"high"`)
|
|
105
|
+
* because an absent level resolves to the unsupported `"minimal"` upstream;
|
|
106
|
+
* other models keep Google's per-model default by leaving the level unset.
|
|
49
107
|
*
|
|
50
|
-
* `
|
|
51
|
-
*
|
|
52
|
-
* gated on `streamThinking` so callers that opted out of streaming thoughts
|
|
53
|
-
* don't pay for thought tokens in the response.
|
|
108
|
+
* `includeThoughts` is gated on `streamThinking` so callers that opted out of
|
|
109
|
+
* streaming thoughts don't pay for thought tokens in the response.
|
|
54
110
|
*/
|
|
55
111
|
function buildThinkingConfig(
|
|
56
112
|
thinking: Record<string, unknown> | undefined,
|
|
113
|
+
model: string,
|
|
57
114
|
): genai.ThinkingConfig | undefined {
|
|
58
115
|
if (!thinking) return undefined;
|
|
116
|
+
const floor = geminiThinkingFloor(model);
|
|
117
|
+
|
|
59
118
|
if (thinking.type === "disabled") {
|
|
60
119
|
return {
|
|
61
|
-
thinkingLevel:
|
|
120
|
+
thinkingLevel: THINKING_LEVEL_BY_NAME[floor],
|
|
62
121
|
includeThoughts: false,
|
|
63
122
|
};
|
|
64
123
|
}
|
|
65
124
|
if (thinking.type !== "adaptive") return undefined;
|
|
66
125
|
|
|
67
126
|
const result: genai.ThinkingConfig = {};
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
127
|
+
if (
|
|
128
|
+
typeof thinking.level === "string" &&
|
|
129
|
+
thinking.level in THINKING_LEVEL_BY_NAME
|
|
130
|
+
) {
|
|
131
|
+
const clamped = clampThinkingLevelToFloor(
|
|
132
|
+
thinking.level as ThinkingLevelName,
|
|
133
|
+
floor,
|
|
134
|
+
);
|
|
135
|
+
result.thinkingLevel = THINKING_LEVEL_BY_NAME[clamped];
|
|
136
|
+
} else if (isGeminiProModel(model)) {
|
|
137
|
+
result.thinkingLevel =
|
|
138
|
+
THINKING_LEVEL_BY_NAME[GEMINI_PRO_DEFAULT_THINKING_LEVEL];
|
|
71
139
|
}
|
|
72
140
|
if (typeof thinking.streamThinking === "boolean") {
|
|
73
141
|
result.includeThoughts = thinking.streamThinking;
|
|
@@ -223,11 +291,9 @@ export class GeminiProvider implements Provider {
|
|
|
223
291
|
|
|
224
292
|
async sendMessage(
|
|
225
293
|
messages: Message[],
|
|
226
|
-
tools?: ToolDefinition[],
|
|
227
|
-
systemPrompt?: string,
|
|
228
294
|
options?: SendMessageOptions,
|
|
229
295
|
): Promise<ProviderResponse> {
|
|
230
|
-
const { config, onEvent, signal } = options ?? {};
|
|
296
|
+
const { tools, systemPrompt, config, onEvent, signal } = options ?? {};
|
|
231
297
|
const configObj = config as Record<string, unknown> | undefined;
|
|
232
298
|
const maxTokens = configObj?.max_tokens as number | undefined;
|
|
233
299
|
const modelOverride = configObj?.model as string | undefined;
|
|
@@ -238,6 +304,7 @@ export class GeminiProvider implements Provider {
|
|
|
238
304
|
const thinkingConfig = geminiModelSupportsThinking(activeModel)
|
|
239
305
|
? buildThinkingConfig(
|
|
240
306
|
configObj?.thinking as Record<string, unknown> | undefined,
|
|
307
|
+
activeModel,
|
|
241
308
|
)
|
|
242
309
|
: undefined;
|
|
243
310
|
|
|
@@ -296,6 +363,7 @@ export class GeminiProvider implements Provider {
|
|
|
296
363
|
let finishReason = "unknown";
|
|
297
364
|
let promptTokens = 0;
|
|
298
365
|
let outputTokens = 0;
|
|
366
|
+
let cachedTokens = 0;
|
|
299
367
|
let responseModel = activeModel;
|
|
300
368
|
|
|
301
369
|
try {
|
|
@@ -343,6 +411,11 @@ export class GeminiProvider implements Provider {
|
|
|
343
411
|
if (chunk.usageMetadata) {
|
|
344
412
|
promptTokens = chunk.usageMetadata.promptTokenCount ?? 0;
|
|
345
413
|
outputTokens = chunk.usageMetadata.candidatesTokenCount ?? 0;
|
|
414
|
+
// Gemini 2.5+/3.x cache a stable request prefix implicitly (on by
|
|
415
|
+
// default). promptTokenCount already includes these cached tokens,
|
|
416
|
+
// so cachedContentTokenCount is the read subset — surface it so the
|
|
417
|
+
// pricing layer applies the discounted cache-read rate.
|
|
418
|
+
cachedTokens = chunk.usageMetadata.cachedContentTokenCount ?? 0;
|
|
346
419
|
}
|
|
347
420
|
|
|
348
421
|
if (chunk.modelVersion) {
|
|
@@ -386,13 +459,18 @@ export class GeminiProvider implements Provider {
|
|
|
386
459
|
usageMetadata: {
|
|
387
460
|
promptTokenCount: promptTokens,
|
|
388
461
|
candidatesTokenCount: outputTokens,
|
|
462
|
+
cachedContentTokenCount: cachedTokens,
|
|
389
463
|
},
|
|
390
464
|
};
|
|
391
465
|
|
|
392
466
|
return {
|
|
393
467
|
content,
|
|
394
468
|
model: responseModel,
|
|
395
|
-
usage: {
|
|
469
|
+
usage: {
|
|
470
|
+
inputTokens: promptTokens,
|
|
471
|
+
outputTokens,
|
|
472
|
+
...(cachedTokens > 0 ? { cacheReadInputTokens: cachedTokens } : {}),
|
|
473
|
+
},
|
|
396
474
|
stopReason: finishReason,
|
|
397
475
|
rawRequest,
|
|
398
476
|
rawResponse,
|
|
@@ -456,7 +534,7 @@ export class GeminiProvider implements Provider {
|
|
|
456
534
|
|
|
457
535
|
for (const msg of messages) {
|
|
458
536
|
const role = msg.role === "assistant" ? "model" : "user";
|
|
459
|
-
const { parts,
|
|
537
|
+
const { parts, toolResultMediaParts } = this.toGeminiParts(
|
|
460
538
|
msg.content,
|
|
461
539
|
toolCallNames,
|
|
462
540
|
model,
|
|
@@ -468,8 +546,8 @@ export class GeminiProvider implements Provider {
|
|
|
468
546
|
// Gemini requires that a Content with functionResponse parts must not
|
|
469
547
|
// contain non-functionResponse parts. Emit tool-result images in a
|
|
470
548
|
// separate user Content entry.
|
|
471
|
-
if (
|
|
472
|
-
result.push({ role: "user", parts:
|
|
549
|
+
if (toolResultMediaParts.length > 0) {
|
|
550
|
+
result.push({ role: "user", parts: toolResultMediaParts });
|
|
473
551
|
}
|
|
474
552
|
}
|
|
475
553
|
|
|
@@ -482,9 +560,9 @@ export class GeminiProvider implements Provider {
|
|
|
482
560
|
toolCallNames: Map<string, string>,
|
|
483
561
|
model: string,
|
|
484
562
|
role: "model" | "user",
|
|
485
|
-
): { parts: genai.Part[];
|
|
563
|
+
): { parts: genai.Part[]; toolResultMediaParts: genai.Part[] } {
|
|
486
564
|
const parts: genai.Part[] = [];
|
|
487
|
-
const
|
|
565
|
+
const toolResultMediaParts: genai.Part[] = [];
|
|
488
566
|
|
|
489
567
|
for (const block of blocks) {
|
|
490
568
|
switch (block.type) {
|
|
@@ -499,14 +577,27 @@ export class GeminiProvider implements Provider {
|
|
|
499
577
|
},
|
|
500
578
|
});
|
|
501
579
|
break;
|
|
502
|
-
case "file":
|
|
580
|
+
case "file": {
|
|
503
581
|
if (this.supportsGeminiInlineFile(block.source.media_type)) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
582
|
+
// Normalize audio MIME onto Gemini's spelling (e.g. audio/mpeg →
|
|
583
|
+
// audio/mp3); PDFs pass through unchanged. Guard the 20 MB inline
|
|
584
|
+
// request limit for audio so an oversize clip degrades to a text
|
|
585
|
+
// note rather than 400ing the whole request.
|
|
586
|
+
const audioMime = normalizeGeminiAudioMime(block.source.media_type);
|
|
587
|
+
const rawBytes = base64ByteLength(block.source.data);
|
|
588
|
+
if (audioMime && rawBytes > GEMINI_MAX_INLINE_AUDIO_BYTES) {
|
|
589
|
+
const approxMb = Math.round(rawBytes / (1024 * 1024));
|
|
590
|
+
parts.push({
|
|
591
|
+
text: `[Audio file too large to send inline: ${block.source.filename} (${block.source.media_type}, ~${approxMb}MB). Gemini's inline request limit is 20MB; this file was omitted. Ask the user for a shorter clip.]`,
|
|
592
|
+
});
|
|
593
|
+
} else {
|
|
594
|
+
parts.push({
|
|
595
|
+
inlineData: {
|
|
596
|
+
mimeType: audioMime ?? block.source.media_type,
|
|
597
|
+
data: block.source.data,
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
}
|
|
510
601
|
} else {
|
|
511
602
|
const fallback = block.extracted_text?.trim()
|
|
512
603
|
? `[Attached file: ${block.source.filename} (${block.source.media_type})]\n${block.extracted_text}`
|
|
@@ -514,6 +605,7 @@ export class GeminiProvider implements Provider {
|
|
|
514
605
|
parts.push({ text: fallback });
|
|
515
606
|
}
|
|
516
607
|
break;
|
|
608
|
+
}
|
|
517
609
|
case "tool_use":
|
|
518
610
|
{
|
|
519
611
|
const functionCallPart: genai.Part = {
|
|
@@ -542,16 +634,39 @@ export class GeminiProvider implements Provider {
|
|
|
542
634
|
if (extraText.length > 0) {
|
|
543
635
|
outputText = outputText + "\n" + extraText.join("\n");
|
|
544
636
|
}
|
|
545
|
-
// Collect images separately — Gemini rejects
|
|
546
|
-
// with functionResponse in the same Content entry.
|
|
637
|
+
// Collect images and inline-able audio separately — Gemini rejects
|
|
638
|
+
// mixing inlineData with functionResponse in the same Content entry.
|
|
547
639
|
for (const cb of block.contentBlocks) {
|
|
548
640
|
if (cb.type === "image") {
|
|
549
|
-
|
|
641
|
+
toolResultMediaParts.push({
|
|
550
642
|
inlineData: {
|
|
551
643
|
mimeType: cb.source.media_type,
|
|
552
644
|
data: cb.source.data,
|
|
553
645
|
},
|
|
554
646
|
});
|
|
647
|
+
} else if (cb.type === "file") {
|
|
648
|
+
const audioMime = normalizeGeminiAudioMime(
|
|
649
|
+
cb.source.media_type,
|
|
650
|
+
);
|
|
651
|
+
if (
|
|
652
|
+
audioMime &&
|
|
653
|
+
base64ByteLength(cb.source.data) <=
|
|
654
|
+
GEMINI_MAX_INLINE_AUDIO_BYTES
|
|
655
|
+
) {
|
|
656
|
+
toolResultMediaParts.push({
|
|
657
|
+
inlineData: { mimeType: audioMime, data: cb.source.data },
|
|
658
|
+
});
|
|
659
|
+
} else if (audioMime) {
|
|
660
|
+
// Oversize audio: note it in the functionResponse output
|
|
661
|
+
// rather than a media part (a text part can't ride the
|
|
662
|
+
// separate media Content, and inline audio would blow
|
|
663
|
+
// Gemini's request-size limit).
|
|
664
|
+
outputText =
|
|
665
|
+
outputText +
|
|
666
|
+
`\n[Audio too large to send inline: ${cb.source.filename}. Ask for a shorter clip.]`;
|
|
667
|
+
}
|
|
668
|
+
// Non-inline-able file sub-blocks (m4a/opus/pdf) are skipped
|
|
669
|
+
// here; the tool's text output already conveys the file.
|
|
555
670
|
}
|
|
556
671
|
}
|
|
557
672
|
}
|
|
@@ -577,7 +692,7 @@ export class GeminiProvider implements Provider {
|
|
|
577
692
|
this.addGemini3UnsignedToolCallFallback(parts, model);
|
|
578
693
|
}
|
|
579
694
|
|
|
580
|
-
return { parts,
|
|
695
|
+
return { parts, toolResultMediaParts };
|
|
581
696
|
}
|
|
582
697
|
|
|
583
698
|
private addGemini3UnsignedToolCallFallback(
|
|
@@ -601,6 +716,9 @@ export class GeminiProvider implements Provider {
|
|
|
601
716
|
}
|
|
602
717
|
|
|
603
718
|
private supportsGeminiInlineFile(mimeType: string): boolean {
|
|
604
|
-
return
|
|
719
|
+
return (
|
|
720
|
+
mimeType === "application/pdf" ||
|
|
721
|
+
normalizeGeminiAudioMime(mimeType) !== null
|
|
722
|
+
);
|
|
605
723
|
}
|
|
606
724
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared source of truth for how Gemini ingests inline audio: which MIME types
|
|
3
|
+
* it accepts, how our stored MIME types normalize onto Gemini's spelling, the
|
|
4
|
+
* inline-request size ceiling, and the token cost.
|
|
5
|
+
*
|
|
6
|
+
* Imported by both the Gemini serializer (`client.ts`) and the token estimator
|
|
7
|
+
* (`context/token-estimator.ts`) so the two cannot drift — if they disagreed on
|
|
8
|
+
* which audio is sent inline, the context budgeter would mis-count what
|
|
9
|
+
* actually goes on the wire.
|
|
10
|
+
*
|
|
11
|
+
* Ref: https://ai.google.dev/gemini-api/docs/audio
|
|
12
|
+
* - Inline-accepted audio: wav, mp3, aiff, aac, ogg, flac
|
|
13
|
+
* - Inline request size limit: 20 MB total (prompt + system + inline files)
|
|
14
|
+
* - Audio is billed at ~32 tokens/second
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Audio MIME types Gemini accepts as inline data, in Gemini's own spelling
|
|
19
|
+
* (the values we emit on the wire). Our upload allowlist stores mp3 as
|
|
20
|
+
* `audio/mpeg`; {@link normalizeGeminiAudioMime} maps that onto `audio/mp3`.
|
|
21
|
+
*/
|
|
22
|
+
export const GEMINI_INLINE_AUDIO_MIME_TYPES = new Set([
|
|
23
|
+
"audio/wav",
|
|
24
|
+
"audio/mp3",
|
|
25
|
+
"audio/aiff",
|
|
26
|
+
"audio/aac",
|
|
27
|
+
"audio/ogg",
|
|
28
|
+
"audio/flac",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Map a stored attachment MIME type onto Gemini's inline-audio spelling, or
|
|
33
|
+
* `null` when Gemini cannot take it inline.
|
|
34
|
+
*
|
|
35
|
+
* m4a (`audio/x-m4a`, `audio/mp4`) and opus are intentionally unsupported:
|
|
36
|
+
* m4a bytes are an MP4 container, not raw AAC, so we must not relabel them as
|
|
37
|
+
* `audio/aac` — they fall through to a text placeholder instead.
|
|
38
|
+
*/
|
|
39
|
+
export function normalizeGeminiAudioMime(mimeType: string): string | null {
|
|
40
|
+
const normalized = mimeType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
41
|
+
const remapped = normalized === "audio/mpeg" ? "audio/mp3" : normalized;
|
|
42
|
+
return GEMINI_INLINE_AUDIO_MIME_TYPES.has(remapped) ? remapped : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Raw byte length backing a base64 string (4 base64 chars → 3 bytes). */
|
|
46
|
+
export function base64ByteLength(base64Data: string): number {
|
|
47
|
+
return Math.floor((base64Data.length * 3) / 4);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Max raw bytes of audio we send inline to Gemini. Gemini's total inline
|
|
52
|
+
* request limit is 20 MB and base64 inflates payloads ~33%, so we cap raw
|
|
53
|
+
* audio at ~12 MB (≈16 MB encoded) to leave headroom for the prompt, system
|
|
54
|
+
* instruction, and conversation history. Larger files degrade to a text
|
|
55
|
+
* placeholder (the Gemini Files API is a future enhancement).
|
|
56
|
+
*/
|
|
57
|
+
export const GEMINI_MAX_INLINE_AUDIO_BYTES = 12 * 1024 * 1024;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Gemini bills audio at ~32 tokens/second, NOT by payload size. We don't have
|
|
61
|
+
* the decoded duration at estimate time, so approximate it from byte size
|
|
62
|
+
* assuming ~128 kbps (~16 KB/s) typical compressed audio. This keeps the
|
|
63
|
+
* context budgeter within range instead of the ~170x over-count that treating
|
|
64
|
+
* the base64 payload as text produces. (Uncompressed WAV is under-counted, but
|
|
65
|
+
* the inline size guard caps it at {@link GEMINI_MAX_INLINE_AUDIO_BYTES}.)
|
|
66
|
+
*/
|
|
67
|
+
const GEMINI_AUDIO_TOKENS_PER_SECOND = 32;
|
|
68
|
+
const APPROX_AUDIO_BYTES_PER_SECOND = 16_000;
|
|
69
|
+
|
|
70
|
+
export function estimateGeminiAudioTokens(base64Data: string): number {
|
|
71
|
+
const approxSeconds =
|
|
72
|
+
base64ByteLength(base64Data) / APPROX_AUDIO_BYTES_PER_SECOND;
|
|
73
|
+
return Math.ceil(approxSeconds * GEMINI_AUDIO_TOKENS_PER_SECOND);
|
|
74
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { isPlaceholderSentinelText } from "../../placeholder-sentinels.js";
|
|
3
4
|
import {
|
|
5
|
+
EMPTY_ASSISTANT_TURN_PLACEHOLDER,
|
|
4
6
|
OpenAIChatCompletionsProvider,
|
|
5
7
|
type OpenAIChatCompletionsProviderOptions,
|
|
6
8
|
} from "../chat-completions-provider.js";
|
|
@@ -74,8 +76,6 @@ async function runStream(
|
|
|
74
76
|
}> {
|
|
75
77
|
const response = await provider.sendMessage(
|
|
76
78
|
[{ role: "user", content: [{ type: "text", text: "hi" }] }],
|
|
77
|
-
undefined,
|
|
78
|
-
undefined,
|
|
79
79
|
{
|
|
80
80
|
onEvent: (e) => {
|
|
81
81
|
events.push(e as { type: string; thinking?: string; text?: string });
|
|
@@ -350,6 +350,116 @@ describe("OpenAIChatCompletionsProvider reasoning parsing", () => {
|
|
|
350
350
|
expect(assistantMsg.reasoning_content).toBeUndefined();
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
+
test("backfills placeholder content for a reasoning-only assistant turn when enabled", async () => {
|
|
354
|
+
const { provider, requests } = stubProvider(
|
|
355
|
+
[
|
|
356
|
+
{
|
|
357
|
+
choices: [{ delta: { content: "ok" }, finish_reason: "stop" }],
|
|
358
|
+
usage: { prompt_tokens: 2, completion_tokens: 1 },
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
{
|
|
362
|
+
assistantReasoningField: "reasoning",
|
|
363
|
+
backfillEmptyAssistantContent: true,
|
|
364
|
+
},
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
await provider.sendMessage([
|
|
368
|
+
{ role: "user", content: [{ type: "text", text: "question" }] },
|
|
369
|
+
{
|
|
370
|
+
role: "assistant",
|
|
371
|
+
content: [
|
|
372
|
+
{
|
|
373
|
+
type: "thinking",
|
|
374
|
+
thinking: "truncated chain of thought",
|
|
375
|
+
signature: "",
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
},
|
|
379
|
+
]);
|
|
380
|
+
|
|
381
|
+
const params = requests[0] as {
|
|
382
|
+
messages: Array<{
|
|
383
|
+
role: string;
|
|
384
|
+
content: string | null;
|
|
385
|
+
reasoning?: string;
|
|
386
|
+
tool_calls?: unknown;
|
|
387
|
+
}>;
|
|
388
|
+
};
|
|
389
|
+
const assistantMsg = params.messages.find((m) => m.role === "assistant")!;
|
|
390
|
+
// content or tool_calls must be set; reasoning alone does not satisfy it.
|
|
391
|
+
expect(assistantMsg.content).toBe(EMPTY_ASSISTANT_TURN_PLACEHOLDER);
|
|
392
|
+
expect(assistantMsg.tool_calls).toBeUndefined();
|
|
393
|
+
expect(assistantMsg.reasoning).toBe("truncated chain of thought");
|
|
394
|
+
// The placeholder is a recognized sentinel, so it is stripped from
|
|
395
|
+
// persisted/rendered history if a model echoes it back, and it carries no
|
|
396
|
+
// control characters that a strict OpenAI-compatible backend might reject.
|
|
397
|
+
expect(isPlaceholderSentinelText(EMPTY_ASSISTANT_TURN_PLACEHOLDER)).toBe(
|
|
398
|
+
true,
|
|
399
|
+
);
|
|
400
|
+
expect(EMPTY_ASSISTANT_TURN_PLACEHOLDER).not.toContain("\x00");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("leaves reasoning-only assistant content null when backfill is disabled", async () => {
|
|
404
|
+
const { provider, requests } = stubProvider(
|
|
405
|
+
[
|
|
406
|
+
{
|
|
407
|
+
choices: [{ delta: { content: "ok" }, finish_reason: "stop" }],
|
|
408
|
+
usage: { prompt_tokens: 2, completion_tokens: 1 },
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
{ assistantReasoningField: "reasoning_content" },
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
await provider.sendMessage([
|
|
415
|
+
{ role: "user", content: [{ type: "text", text: "question" }] },
|
|
416
|
+
{
|
|
417
|
+
role: "assistant",
|
|
418
|
+
content: [
|
|
419
|
+
{
|
|
420
|
+
type: "thinking",
|
|
421
|
+
thinking: "truncated chain of thought",
|
|
422
|
+
signature: "",
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
]);
|
|
427
|
+
|
|
428
|
+
const params = requests[0] as {
|
|
429
|
+
messages: Array<{ role: string; content: string | null }>;
|
|
430
|
+
};
|
|
431
|
+
const assistantMsg = params.messages.find((m) => m.role === "assistant")!;
|
|
432
|
+
// Backfill defaults off, so providers that tolerate null assistant content
|
|
433
|
+
// (e.g. OpenAI proper) are unaffected by the OpenRouter-specific guard.
|
|
434
|
+
expect(assistantMsg.content).toBeNull();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test("does not backfill content when tool calls are present", async () => {
|
|
438
|
+
const { provider, requests } = stubProvider([
|
|
439
|
+
{
|
|
440
|
+
choices: [{ delta: { content: "ok" }, finish_reason: "stop" }],
|
|
441
|
+
usage: { prompt_tokens: 2, completion_tokens: 1 },
|
|
442
|
+
},
|
|
443
|
+
]);
|
|
444
|
+
|
|
445
|
+
await provider.sendMessage([
|
|
446
|
+
{
|
|
447
|
+
role: "assistant",
|
|
448
|
+
content: [
|
|
449
|
+
{ type: "tool_use", id: "call_1", name: "search", input: { q: "x" } },
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
]);
|
|
453
|
+
|
|
454
|
+
const params = requests[0] as {
|
|
455
|
+
messages: Array<{ role: string; content: string | null }>;
|
|
456
|
+
};
|
|
457
|
+
// Tool-call-only assistant messages keep null content (preferred by
|
|
458
|
+
// Anthropic-proxy/Bedrock backends); the placeholder is only for the
|
|
459
|
+
// neither-content-nor-tool_calls case.
|
|
460
|
+
expect(params.messages[0].content).toBeNull();
|
|
461
|
+
});
|
|
462
|
+
|
|
353
463
|
test("skips Anthropic-originated thinking blocks (with signatures)", async () => {
|
|
354
464
|
const { provider, requests } = stubProvider(
|
|
355
465
|
[
|
|
@@ -4,6 +4,7 @@ import { isAbortReason } from "../../util/abort-reasons.js";
|
|
|
4
4
|
import { ProviderError } from "../../util/errors.js";
|
|
5
5
|
import { extractRetryAfterMs } from "../../util/retry.js";
|
|
6
6
|
import { escapeXmlAttr } from "../../util/xml.js";
|
|
7
|
+
import { PLACEHOLDER_EMPTY_TURN } from "../placeholder-sentinels.js";
|
|
7
8
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
8
9
|
import type {
|
|
9
10
|
ContentBlock,
|
|
@@ -11,7 +12,6 @@ import type {
|
|
|
11
12
|
Provider,
|
|
12
13
|
ProviderResponse,
|
|
13
14
|
SendMessageOptions,
|
|
14
|
-
ToolDefinition,
|
|
15
15
|
} from "../types.js";
|
|
16
16
|
import {
|
|
17
17
|
ContextOverflowError,
|
|
@@ -101,6 +101,26 @@ export function extractApiErrorDetail(
|
|
|
101
101
|
* OpenRouter's `error.metadata.raw` strings, which are typically <1KB. */
|
|
102
102
|
const MAX_API_ERROR_DETAIL_CHARS = 2000;
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Fallback `content` for an assistant turn that has neither visible text nor
|
|
106
|
+
* tool calls (e.g. a reasoning-only turn truncated at the output-token limit).
|
|
107
|
+
*
|
|
108
|
+
* The OpenAI chat-completions schema requires an assistant message to carry
|
|
109
|
+
* `content` or `tool_calls`. OpenAI itself tolerates `content: null`/`""` here,
|
|
110
|
+
* but strict OpenAI-compatible backends do not: DeepSeek via OpenRouter rejects
|
|
111
|
+
* the request with `Invalid assistant message: content or tool_calls must be
|
|
112
|
+
* set`, and vLLM-style validators coerce empty-string content back to null and
|
|
113
|
+
* reject it the same way. The placeholder must therefore be a non-empty string.
|
|
114
|
+
*
|
|
115
|
+
* We reuse the shared empty-turn sentinel so that
|
|
116
|
+
* `isPlaceholderSentinelText`/`cleanAssistantContent` strip it from persisted
|
|
117
|
+
* and rendered history if a model ever echoes it back. The null-byte prefix is
|
|
118
|
+
* dropped because some OpenAI-compatible backends reject control characters in
|
|
119
|
+
* message content; the bare form is still recognized by
|
|
120
|
+
* `isPlaceholderSentinelText`.
|
|
121
|
+
*/
|
|
122
|
+
export const EMPTY_ASSISTANT_TURN_PLACEHOLDER = PLACEHOLDER_EMPTY_TURN.slice(1);
|
|
123
|
+
|
|
104
124
|
/**
|
|
105
125
|
* Read the first matching header from an SDK error's headers object,
|
|
106
126
|
* tolerating both Map-like (`Headers.get()`) and plain-object shapes.
|
|
@@ -154,6 +174,13 @@ export interface OpenAIChatCompletionsProviderOptions {
|
|
|
154
174
|
* DeepSeek/Fireworks use `"reasoning_content"`; OpenRouter uses `"reasoning"`.
|
|
155
175
|
* When unset, thinking blocks are dropped from outbound assistant messages. */
|
|
156
176
|
assistantReasoningField?: "reasoning" | "reasoning_content";
|
|
177
|
+
/** Backfill a non-empty placeholder for assistant turns that would otherwise
|
|
178
|
+
* serialize with neither `content` nor `tool_calls` (e.g. reasoning-only
|
|
179
|
+
* turns). Off by default; enabled for OpenRouter, whose downstream providers
|
|
180
|
+
* (e.g. DeepSeek) reject such messages with `Invalid assistant message:
|
|
181
|
+
* content or tool_calls must be set`. See {@link
|
|
182
|
+
* EMPTY_ASSISTANT_TURN_PLACEHOLDER}. */
|
|
183
|
+
backfillEmptyAssistantContent?: boolean;
|
|
157
184
|
}
|
|
158
185
|
|
|
159
186
|
/** Wire-level reasoning_effort values. The OpenAI SDK type doesn't include
|
|
@@ -229,6 +256,7 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
229
256
|
| "reasoning"
|
|
230
257
|
| "reasoning_content"
|
|
231
258
|
| undefined;
|
|
259
|
+
private backfillEmptyAssistantContent: boolean;
|
|
232
260
|
|
|
233
261
|
constructor(
|
|
234
262
|
apiKey: string,
|
|
@@ -252,15 +280,15 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
252
280
|
this.requestHeaders = options.requestHeaders ?? {};
|
|
253
281
|
this.parseThinkTags = options.parseThinkTags ?? false;
|
|
254
282
|
this.assistantReasoningField = options.assistantReasoningField;
|
|
283
|
+
this.backfillEmptyAssistantContent =
|
|
284
|
+
options.backfillEmptyAssistantContent ?? false;
|
|
255
285
|
}
|
|
256
286
|
|
|
257
287
|
async sendMessage(
|
|
258
288
|
messages: Message[],
|
|
259
|
-
tools?: ToolDefinition[],
|
|
260
|
-
systemPrompt?: string,
|
|
261
289
|
options?: SendMessageOptions,
|
|
262
290
|
): Promise<ProviderResponse> {
|
|
263
|
-
const { config, onEvent, signal } = options ?? {};
|
|
291
|
+
const { tools, systemPrompt, config, onEvent, signal } = options ?? {};
|
|
264
292
|
const configObj = config as Record<string, unknown> | undefined;
|
|
265
293
|
const maxTokens = configObj?.max_tokens as number | undefined;
|
|
266
294
|
const modelOverride = configObj?.model as string | undefined;
|
|
@@ -797,6 +825,19 @@ export class OpenAIChatCompletionsProvider implements Provider {
|
|
|
797
825
|
result.tool_calls = toolCalls;
|
|
798
826
|
}
|
|
799
827
|
|
|
828
|
+
// An assistant message must carry `content` or `tool_calls`. A turn with
|
|
829
|
+
// neither (e.g. reasoning-only) would serialize to null/empty content with
|
|
830
|
+
// no tool calls, which strict OpenAI-compatible backends reject. Reasoning
|
|
831
|
+
// lives in a separate field and does not satisfy this constraint. Scoped to
|
|
832
|
+
// providers that need it (OpenRouter) via `backfillEmptyAssistantContent`.
|
|
833
|
+
if (
|
|
834
|
+
this.backfillEmptyAssistantContent &&
|
|
835
|
+
!result.tool_calls &&
|
|
836
|
+
(result.content === null || result.content === "")
|
|
837
|
+
) {
|
|
838
|
+
result.content = EMPTY_ASSISTANT_TURN_PLACEHOLDER;
|
|
839
|
+
}
|
|
840
|
+
|
|
800
841
|
return result;
|
|
801
842
|
}
|
|
802
843
|
|
|
@@ -12,7 +12,6 @@ import type {
|
|
|
12
12
|
Provider,
|
|
13
13
|
ProviderResponse,
|
|
14
14
|
SendMessageOptions,
|
|
15
|
-
ToolDefinition,
|
|
16
15
|
} from "../types.js";
|
|
17
16
|
import { ContextOverflowError } from "../types.js";
|
|
18
17
|
import { detectOpenAICompatibleContextOverflow } from "./chat-completions-provider.js";
|
|
@@ -160,11 +159,9 @@ export class OpenAIResponsesProvider implements Provider {
|
|
|
160
159
|
|
|
161
160
|
async sendMessage(
|
|
162
161
|
messages: Message[],
|
|
163
|
-
tools?: ToolDefinition[],
|
|
164
|
-
systemPrompt?: string,
|
|
165
162
|
options?: SendMessageOptions,
|
|
166
163
|
): Promise<ProviderResponse> {
|
|
167
|
-
const { config, onEvent, signal } = options ?? {};
|
|
164
|
+
const { tools, systemPrompt, config, onEvent, signal } = options ?? {};
|
|
168
165
|
const configObj = config as Record<string, unknown> | undefined;
|
|
169
166
|
const maxTokens = configObj?.max_tokens as number | undefined;
|
|
170
167
|
const modelOverride = configObj?.model as string | undefined;
|