@vellumai/assistant 0.8.5 → 0.8.6
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 +33 -1
- package/ARCHITECTURE.md +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +1900 -166
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +5 -4
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- package/src/__tests__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/auth/route-policy.ts +10 -0
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type BackgroundWakeIntent,
|
|
5
|
+
computeNextBackgroundWakeIntent,
|
|
6
|
+
} from "../../background-wake/next-wake.js";
|
|
7
|
+
import type { BackgroundWakeRuntime } from "../../background-wake/runtime-registry.js";
|
|
4
8
|
import { getBackgroundWakeRuntime } from "../../background-wake/runtime-registry.js";
|
|
9
|
+
import { getLogger } from "../../util/logger.js";
|
|
5
10
|
import { BadRequestError, ServiceUnavailableError } from "./errors.js";
|
|
6
11
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
7
12
|
|
|
8
13
|
const PREPARE_SLEEP_DEFER_WINDOW_MS = 60_000;
|
|
9
14
|
const HEARTBEAT_DUE_TOLERANCE_MS = 1_000;
|
|
15
|
+
const MIN_DRAIN_START_BUDGET_MS = 5_000;
|
|
16
|
+
const LEASE_RENEW_INTERVAL_MS = 120_000;
|
|
17
|
+
const log = getLogger("background-wake-routes");
|
|
18
|
+
|
|
19
|
+
class DrainDeadlineElapsedError extends Error {
|
|
20
|
+
constructor() {
|
|
21
|
+
super("background wake lease deadline elapsed before starting work");
|
|
22
|
+
this.name = "DrainDeadlineElapsedError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type RenewWakeLease = (leaseId: string) => Promise<unknown>;
|
|
27
|
+
type CompleteWakeLease = (args: {
|
|
28
|
+
leaseId: string;
|
|
29
|
+
status: "completed" | "failed" | "expired";
|
|
30
|
+
error?: string;
|
|
31
|
+
nextIntent?: BackgroundWakeIntent | null;
|
|
32
|
+
}) => Promise<unknown>;
|
|
10
33
|
|
|
11
34
|
let computeWakeIntent = computeNextBackgroundWakeIntent;
|
|
35
|
+
let renewWakeLease: RenewWakeLease = defaultRenewWakeLease;
|
|
36
|
+
let completeWakeLease: CompleteWakeLease = defaultCompleteWakeLease;
|
|
37
|
+
const activeDrainLeases = new Set<string>();
|
|
38
|
+
const activeDrainPromises = new Set<Promise<void>>();
|
|
12
39
|
const timestampInputSchema = z.union([z.number(), z.string()]);
|
|
13
40
|
|
|
14
41
|
const wakeIntentSchema = z
|
|
@@ -66,7 +93,8 @@ function normalizeTimestamp(value: unknown): unknown {
|
|
|
66
93
|
return Number.isFinite(parsed) ? parsed : value;
|
|
67
94
|
}
|
|
68
95
|
|
|
69
|
-
|
|
96
|
+
type DrainDueRequest = z.infer<typeof normalizedDrainDueRequestSchema>;
|
|
97
|
+
function parseDrainDueBody(body: Record<string, unknown>): DrainDueRequest {
|
|
70
98
|
const parsed = normalizedDrainDueRequestSchema.safeParse(
|
|
71
99
|
normalizeDrainDueBody(body),
|
|
72
100
|
);
|
|
@@ -78,6 +106,20 @@ function parseDrainDueBody(body: Record<string, unknown>) {
|
|
|
78
106
|
return parsed.data;
|
|
79
107
|
}
|
|
80
108
|
|
|
109
|
+
async function defaultRenewWakeLease(leaseId: string): Promise<unknown> {
|
|
110
|
+
const { renewBackgroundWakeLease } =
|
|
111
|
+
await import("../../background-wake/platform-client.js");
|
|
112
|
+
return renewBackgroundWakeLease(leaseId);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function defaultCompleteWakeLease(
|
|
116
|
+
args: Parameters<CompleteWakeLease>[0],
|
|
117
|
+
): Promise<unknown> {
|
|
118
|
+
const { completeBackgroundWakeLease } =
|
|
119
|
+
await import("../../background-wake/platform-client.js");
|
|
120
|
+
return completeBackgroundWakeLease(args);
|
|
121
|
+
}
|
|
122
|
+
|
|
81
123
|
function handleGetIntent() {
|
|
82
124
|
return { intent: computeWakeIntent() };
|
|
83
125
|
}
|
|
@@ -102,28 +144,141 @@ async function handleDrainDue(body: Record<string, unknown>) {
|
|
|
102
144
|
);
|
|
103
145
|
}
|
|
104
146
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
147
|
+
if (!activeDrainLeases.has(request.leaseId)) {
|
|
148
|
+
activeDrainLeases.add(request.leaseId);
|
|
149
|
+
const drainPromise = runDrainDueLease(request, runtime);
|
|
150
|
+
activeDrainPromises.add(drainPromise);
|
|
151
|
+
void drainPromise.finally(() => activeDrainPromises.delete(drainPromise));
|
|
152
|
+
}
|
|
111
153
|
|
|
112
154
|
return {
|
|
155
|
+
accepted: true,
|
|
113
156
|
leaseId: request.leaseId,
|
|
114
157
|
reason: request.reason,
|
|
115
158
|
sourceGeneration: request.sourceGeneration,
|
|
116
159
|
startedAt: request.startedAt,
|
|
117
160
|
deadlineAt: request.deadlineAt,
|
|
118
|
-
counts: {
|
|
119
|
-
heartbeat: heartbeatRan ? 1 : 0,
|
|
120
|
-
scheduler: scheduledCount,
|
|
121
|
-
total: (heartbeatRan ? 1 : 0) + scheduledCount,
|
|
122
|
-
},
|
|
123
|
-
nextIntent: computeWakeIntent(),
|
|
124
161
|
};
|
|
125
162
|
}
|
|
126
163
|
|
|
164
|
+
async function runDrainDueLease(
|
|
165
|
+
request: DrainDueRequest,
|
|
166
|
+
runtime: BackgroundWakeRuntime,
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
let renewTimer: ReturnType<typeof setInterval> | undefined;
|
|
169
|
+
try {
|
|
170
|
+
renewTimer = setInterval(() => {
|
|
171
|
+
void renewWakeLease(request.leaseId).catch(() => {});
|
|
172
|
+
}, LEASE_RENEW_INTERVAL_MS);
|
|
173
|
+
renewTimer.unref?.();
|
|
174
|
+
|
|
175
|
+
assertDrainCanStart(request.deadlineAt);
|
|
176
|
+
const result = await performDrainDue(request, runtime);
|
|
177
|
+
await reportLeaseCompletion({
|
|
178
|
+
leaseId: request.leaseId,
|
|
179
|
+
status: "completed",
|
|
180
|
+
nextIntent: result.nextIntent,
|
|
181
|
+
});
|
|
182
|
+
} catch (error) {
|
|
183
|
+
await reportLeaseCompletion({
|
|
184
|
+
leaseId: request.leaseId,
|
|
185
|
+
status: completionStatusForError(error),
|
|
186
|
+
error: error instanceof Error ? error.message : String(error),
|
|
187
|
+
nextIntent: computeWakeIntent(),
|
|
188
|
+
});
|
|
189
|
+
} finally {
|
|
190
|
+
if (renewTimer) clearInterval(renewTimer);
|
|
191
|
+
activeDrainLeases.delete(request.leaseId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function reportLeaseCompletion(
|
|
196
|
+
args: Parameters<CompleteWakeLease>[0],
|
|
197
|
+
): Promise<void> {
|
|
198
|
+
try {
|
|
199
|
+
await completeWakeLease(args);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
log.warn(
|
|
202
|
+
{ err, leaseId: args.leaseId, status: args.status },
|
|
203
|
+
"Failed to report background wake lease completion",
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function performDrainDue(
|
|
209
|
+
request: DrainDueRequest,
|
|
210
|
+
runtime: BackgroundWakeRuntime,
|
|
211
|
+
) {
|
|
212
|
+
const now = Date.now();
|
|
213
|
+
const currentIntent = computeWakeIntent(now);
|
|
214
|
+
const heartbeatDue = isHeartbeatTimerDue(runtime.heartbeat.nextRunAt, now);
|
|
215
|
+
const schedulerDue =
|
|
216
|
+
heartbeatDue ||
|
|
217
|
+
reasonIncludesSource(request.reason, "schedule") ||
|
|
218
|
+
intentHasDueSource(currentIntent, "schedule", now);
|
|
219
|
+
|
|
220
|
+
if (heartbeatDue) {
|
|
221
|
+
if (hasStartBudget(request.deadlineAt)) {
|
|
222
|
+
await runtime.heartbeat.runManagedWakeIfDue({
|
|
223
|
+
now,
|
|
224
|
+
toleranceMs: HEARTBEAT_DUE_TOLERANCE_MS,
|
|
225
|
+
scheduledFor: request.startedAt,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (schedulerDue) {
|
|
231
|
+
await runtime.scheduler.runDueWorkOnce({
|
|
232
|
+
deadlineAt: request.deadlineAt,
|
|
233
|
+
minStartBudgetMs: MIN_DRAIN_START_BUDGET_MS,
|
|
234
|
+
includeStillPending: true,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const nextIntent = computeWakeIntent();
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
nextIntent,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function assertDrainCanStart(deadlineAt: number): void {
|
|
246
|
+
if (deadlineAt <= Date.now()) {
|
|
247
|
+
throw new DrainDeadlineElapsedError();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function completionStatusForError(error: unknown): "failed" | "expired" {
|
|
252
|
+
return error instanceof DrainDeadlineElapsedError ? "expired" : "failed";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function reasonIncludesSource(
|
|
256
|
+
reason: string,
|
|
257
|
+
source: "heartbeat" | "schedule",
|
|
258
|
+
): boolean {
|
|
259
|
+
return reason === "mixed" || reason === source;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function isHeartbeatTimerDue(nextRunAt: number | null, now: number): boolean {
|
|
263
|
+
return nextRunAt != null && nextRunAt <= now + HEARTBEAT_DUE_TOLERANCE_MS;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function intentHasDueSource(
|
|
267
|
+
intent: BackgroundWakeIntent | null,
|
|
268
|
+
source: "heartbeat" | "schedule",
|
|
269
|
+
now: number,
|
|
270
|
+
): boolean {
|
|
271
|
+
return (
|
|
272
|
+
intent != null &&
|
|
273
|
+
intent.actualNextDueAt <= now + HEARTBEAT_DUE_TOLERANCE_MS &&
|
|
274
|
+
reasonIncludesSource(intent.reason, source)
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function hasStartBudget(deadlineAt: number): boolean {
|
|
279
|
+
return deadlineAt - Date.now() >= MIN_DRAIN_START_BUDGET_MS;
|
|
280
|
+
}
|
|
281
|
+
|
|
127
282
|
/** @internal Test helper for route-only tests. */
|
|
128
283
|
export function setBackgroundWakeIntentComputerForTest(
|
|
129
284
|
nextCompute: typeof computeNextBackgroundWakeIntent | null,
|
|
@@ -131,6 +286,24 @@ export function setBackgroundWakeIntentComputerForTest(
|
|
|
131
286
|
computeWakeIntent = nextCompute ?? computeNextBackgroundWakeIntent;
|
|
132
287
|
}
|
|
133
288
|
|
|
289
|
+
/** @internal Test helper for route-only tests. */
|
|
290
|
+
export function setBackgroundWakeLeaseClientForTest(
|
|
291
|
+
nextClient: {
|
|
292
|
+
renew: RenewWakeLease;
|
|
293
|
+
complete: CompleteWakeLease;
|
|
294
|
+
} | null,
|
|
295
|
+
): void {
|
|
296
|
+
renewWakeLease = nextClient?.renew ?? defaultRenewWakeLease;
|
|
297
|
+
completeWakeLease = nextClient?.complete ?? defaultCompleteWakeLease;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** @internal Test helper for route-only tests. */
|
|
301
|
+
export async function flushBackgroundWakeDrainsForTest(): Promise<void> {
|
|
302
|
+
while (activeDrainPromises.size > 0) {
|
|
303
|
+
await Promise.allSettled([...activeDrainPromises]);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
134
307
|
export const ROUTES: RouteDefinition[] = [
|
|
135
308
|
{
|
|
136
309
|
operationId: "getBackgroundWakeIntent",
|
|
@@ -171,17 +344,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
171
344
|
tags: ["background-wake"],
|
|
172
345
|
requestBody: drainDueRequestSchema,
|
|
173
346
|
responseBody: z.object({
|
|
347
|
+
accepted: z.boolean(),
|
|
174
348
|
leaseId: z.string(),
|
|
175
349
|
reason: z.string(),
|
|
176
350
|
sourceGeneration: z.string(),
|
|
177
351
|
startedAt: z.number(),
|
|
178
352
|
deadlineAt: z.number(),
|
|
179
|
-
counts: z.object({
|
|
180
|
-
heartbeat: z.number(),
|
|
181
|
-
scheduler: z.number(),
|
|
182
|
-
total: z.number(),
|
|
183
|
-
}),
|
|
184
|
-
nextIntent: wakeIntentSchema,
|
|
185
353
|
}),
|
|
186
354
|
handler: ({ body }: RouteHandlerArgs) => handleDrainDue(body ?? {}),
|
|
187
355
|
},
|
|
@@ -19,9 +19,9 @@ import { z } from "zod";
|
|
|
19
19
|
import { getConfig } from "../../config/loader.js";
|
|
20
20
|
import { readNowScratchpad } from "../../daemon/conversation-runtime-assembly.js";
|
|
21
21
|
import { getOrCreateConversation } from "../../daemon/conversation-store.js";
|
|
22
|
-
import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
|
|
23
22
|
import { parseIdentityFields } from "../../daemon/handlers/identity.js";
|
|
24
23
|
import { getConversationByKey } from "../../memory/conversation-key-store.js";
|
|
24
|
+
import { getAllToolDefinitions } from "../../tools/registry.js";
|
|
25
25
|
import { getLogger } from "../../util/logger.js";
|
|
26
26
|
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
27
27
|
import { runBtwSidechain } from "../btw-sidechain.js";
|
|
@@ -77,7 +77,7 @@ async function handleBtw({
|
|
|
77
77
|
fastText = `Hi, I'm ${fields.name}!`;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
fastText ??= getCachedIntro()?.
|
|
80
|
+
fastText ??= getCachedIntro()?.greetings[0];
|
|
81
81
|
if (fastText) {
|
|
82
82
|
log.debug("Returning identity intro fast-path");
|
|
83
83
|
return new ReadableStream({
|
|
@@ -122,7 +122,7 @@ async function handleBtw({
|
|
|
122
122
|
const result = await runBtwSidechain({
|
|
123
123
|
content: effectiveContent,
|
|
124
124
|
conversation,
|
|
125
|
-
tools:
|
|
125
|
+
tools: getAllToolDefinitions(),
|
|
126
126
|
signal: abortSignal,
|
|
127
127
|
...(isGreeting ? { callSite: "emptyStateGreeting" as const } : {}),
|
|
128
128
|
onEvent: (event) => {
|
|
@@ -146,7 +146,7 @@ async function handleBtw({
|
|
|
146
146
|
|
|
147
147
|
if (isIntroRequest && result.text) {
|
|
148
148
|
try {
|
|
149
|
-
setCachedIntro(result.text);
|
|
149
|
+
setCachedIntro([result.text]);
|
|
150
150
|
log.debug("Cached identity intro text");
|
|
151
151
|
} catch {
|
|
152
152
|
// Non-fatal — next request will regenerate.
|
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
* errors, and build the success response.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
12
14
|
import { analyzeConversation } from "../services/analyze-conversation.js";
|
|
13
15
|
import { buildConversationDetailResponse } from "../services/conversation-serializer.js";
|
|
16
|
+
import { conversationSummarySchema } from "./conversation-list-routes.js";
|
|
14
17
|
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
15
18
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
16
19
|
|
|
@@ -60,6 +63,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
60
63
|
description:
|
|
61
64
|
"Create a new conversation with a structured self-assessment of an existing conversation.",
|
|
62
65
|
tags: ["conversations"],
|
|
66
|
+
responseBody: z.object({
|
|
67
|
+
conversation: conversationSummarySchema,
|
|
68
|
+
}),
|
|
63
69
|
handler: handleAnalyzeConversation,
|
|
64
70
|
},
|
|
65
71
|
];
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route definitions for the per-conversation **compaction trail** view.
|
|
3
|
+
*
|
|
4
|
+
* GET /v1/conversations/:id/compaction?callId=…
|
|
5
|
+
*
|
|
6
|
+
* Reachable via the platform's `RuntimeProxyWildcardView` at
|
|
7
|
+
* `/v1/assistants/{assistantId}/conversations/{conversationId}/compaction/?callId=…`.
|
|
8
|
+
*
|
|
9
|
+
* # Scope
|
|
10
|
+
*
|
|
11
|
+
* Returns the set of `call_site = "compactionAgent"` rows in this
|
|
12
|
+
* conversation that ran in the **window between the previous real LLM
|
|
13
|
+
* call and the one identified by `callId`**, ordered chronologically.
|
|
14
|
+
* This is the data the Inspector's "Compaction" tab shows when you
|
|
15
|
+
* select a call in the rail: it answers "what did the compactor do to
|
|
16
|
+
* my context before *this specific* call?" — not "what has the
|
|
17
|
+
* compactor ever done in this conversation".
|
|
18
|
+
*
|
|
19
|
+
* The floor is resolved by walking back from the selected call to the
|
|
20
|
+
* most recent non-`compactionAgent` row in the same conversation. When
|
|
21
|
+
* the selected call is the *first* real call in the conversation,
|
|
22
|
+
* there is no floor and every preceding compaction is in scope.
|
|
23
|
+
*
|
|
24
|
+
* # Data model decision (in progress)
|
|
25
|
+
*
|
|
26
|
+
* Today the trail is projected from `llm_request_logs` rows alone — no
|
|
27
|
+
* `compaction_logs` table exists yet (#32055 remains a draft). This MVP
|
|
28
|
+
* route exists precisely to test whether the projected shape is enough.
|
|
29
|
+
* If real-world use surfaces UX needs that aren't in `llm_request_logs`
|
|
30
|
+
* (most likely: per-event duration, structured before/after counts,
|
|
31
|
+
* trigger reason), that becomes the concrete justification for the new
|
|
32
|
+
* table. Until then, missing fields surface as `null` and the Compaction
|
|
33
|
+
* tab renders `"Unavailable"` for them.
|
|
34
|
+
*
|
|
35
|
+
* In particular, `durationMs` is always `null` for now — the column
|
|
36
|
+
* doesn't exist on `llm_request_logs` and we deliberately ship the route
|
|
37
|
+
* without it to surface the gap in the UI.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
import { z } from "zod";
|
|
41
|
+
|
|
42
|
+
import { getConversation } from "../../memory/conversation-crud.js";
|
|
43
|
+
import { getLlmRequestLogSource } from "../../memory/llm-request-log-source.js";
|
|
44
|
+
import type { LogRow } from "../../memory/llm-request-log-store.js";
|
|
45
|
+
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
46
|
+
import {
|
|
47
|
+
type LlmContextSummary,
|
|
48
|
+
normalizeLlmContextPayloads,
|
|
49
|
+
} from "./llm-context-normalization.js";
|
|
50
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Wire shape for a single compaction event. Mirrors the React Query
|
|
54
|
+
* response type at
|
|
55
|
+
* `apps/web/src/domains/chat/inspector/compaction-trail-types.ts`.
|
|
56
|
+
* Keep the two in sync — until the OpenAPI client generator picks up
|
|
57
|
+
* this route, the frontend type is hand-maintained.
|
|
58
|
+
*/
|
|
59
|
+
export interface CompactionTrailEvent {
|
|
60
|
+
id: string;
|
|
61
|
+
createdAt: number;
|
|
62
|
+
model: string | null;
|
|
63
|
+
provider: string | null;
|
|
64
|
+
inputTokens: number | null;
|
|
65
|
+
outputTokens: number | null;
|
|
66
|
+
/**
|
|
67
|
+
* Per-call wall-clock latency, in milliseconds. **Always `null` for
|
|
68
|
+
* now** — `llm_request_logs` doesn't carry a duration column. Surfacing
|
|
69
|
+
* the gap in the UI is intentional: if engineers consistently miss
|
|
70
|
+
* having latency here, that's a concrete signal to extend the row
|
|
71
|
+
* (either as a column on `llm_request_logs` or on a dedicated
|
|
72
|
+
* `compaction_logs` table per the open data-model decision).
|
|
73
|
+
*/
|
|
74
|
+
durationMs: number | null;
|
|
75
|
+
responsePreview: string | null;
|
|
76
|
+
requestMessageCount: number | null;
|
|
77
|
+
stopReason: string | null;
|
|
78
|
+
estimatedCostUsd: number | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CompactionTrailResponse {
|
|
82
|
+
conversationId: string;
|
|
83
|
+
events: CompactionTrailEvent[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const compactionTrailEventSchema = z.object({
|
|
87
|
+
id: z.string(),
|
|
88
|
+
createdAt: z.number(),
|
|
89
|
+
model: z.string().nullable(),
|
|
90
|
+
provider: z.string().nullable(),
|
|
91
|
+
inputTokens: z.number().nullable(),
|
|
92
|
+
outputTokens: z.number().nullable(),
|
|
93
|
+
durationMs: z.number().nullable(),
|
|
94
|
+
responsePreview: z.string().nullable(),
|
|
95
|
+
requestMessageCount: z.number().nullable(),
|
|
96
|
+
stopReason: z.string().nullable(),
|
|
97
|
+
estimatedCostUsd: z.number().nullable(),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const compactionTrailResponseSchema = z.object({
|
|
101
|
+
conversationId: z.string(),
|
|
102
|
+
events: z.array(compactionTrailEventSchema),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Projection — LogRow → CompactionTrailEvent
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function tryParseJson(value: string): unknown {
|
|
110
|
+
try {
|
|
111
|
+
return JSON.parse(value);
|
|
112
|
+
} catch {
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Project a raw `llm_request_logs` row into the compaction-trail wire
|
|
119
|
+
* shape. Reuses `normalizeLlmContextPayloads` so model/provider/token
|
|
120
|
+
* extraction stays consistent with what the rest of the inspector shows.
|
|
121
|
+
*
|
|
122
|
+
* Fields the normalizer can't derive (today: `durationMs`) land as
|
|
123
|
+
* `null` — see the `CompactionTrailEvent.durationMs` doc comment for the
|
|
124
|
+
* rationale.
|
|
125
|
+
*
|
|
126
|
+
* Exported only for unit tests; the route handler is the sole production
|
|
127
|
+
* caller.
|
|
128
|
+
*/
|
|
129
|
+
export function projectLogRowToCompactionTrailEvent(
|
|
130
|
+
log: LogRow,
|
|
131
|
+
): CompactionTrailEvent {
|
|
132
|
+
const normalized = normalizeLlmContextPayloads({
|
|
133
|
+
requestPayload: tryParseJson(log.requestPayload),
|
|
134
|
+
responsePayload: tryParseJson(log.responsePayload),
|
|
135
|
+
createdAt: log.createdAt,
|
|
136
|
+
});
|
|
137
|
+
const summary: LlmContextSummary | undefined = normalized.summary;
|
|
138
|
+
return {
|
|
139
|
+
id: log.id,
|
|
140
|
+
createdAt: log.createdAt,
|
|
141
|
+
model: summary?.model ?? null,
|
|
142
|
+
// Prefer the normalized provider (derived from payload shape) over
|
|
143
|
+
// the stored column. Stored `provider` is the originating call's
|
|
144
|
+
// own identifier and matches the normalizer in all cases we ship
|
|
145
|
+
// today, but the normalizer is the source-of-truth used by sibling
|
|
146
|
+
// inspector tabs — keep that alignment.
|
|
147
|
+
provider: summary?.provider ?? log.provider ?? null,
|
|
148
|
+
inputTokens: summary?.inputTokens ?? null,
|
|
149
|
+
outputTokens: summary?.outputTokens ?? null,
|
|
150
|
+
durationMs: null,
|
|
151
|
+
responsePreview: summary?.responsePreview ?? null,
|
|
152
|
+
requestMessageCount: summary?.requestMessageCount ?? null,
|
|
153
|
+
stopReason: summary?.stopReason ?? null,
|
|
154
|
+
estimatedCostUsd: summary?.estimatedCostUsd ?? null,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// Handler
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
async function handleGetCompactionTrail({
|
|
163
|
+
pathParams = {},
|
|
164
|
+
queryParams = {},
|
|
165
|
+
}: RouteHandlerArgs): Promise<CompactionTrailResponse> {
|
|
166
|
+
const conversationId = pathParams.id;
|
|
167
|
+
const callId = queryParams.callId;
|
|
168
|
+
|
|
169
|
+
if (!conversationId) {
|
|
170
|
+
throw new BadRequestError("conversation id path parameter is required");
|
|
171
|
+
}
|
|
172
|
+
if (!callId) {
|
|
173
|
+
throw new BadRequestError("callId query parameter is required");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Verify the conversation exists before we touch the log source —
|
|
177
|
+
// a missing conversation should 404, not return an empty trail with
|
|
178
|
+
// no signal that the caller had the wrong id.
|
|
179
|
+
const conversation = getConversation(conversationId);
|
|
180
|
+
if (!conversation) {
|
|
181
|
+
throw new NotFoundError(`Conversation ${conversationId} not found`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const source = await getLlmRequestLogSource();
|
|
185
|
+
const selectedCall = await source.getRequestLogById(callId);
|
|
186
|
+
if (!selectedCall) {
|
|
187
|
+
throw new NotFoundError(`LLM call ${callId} not found`);
|
|
188
|
+
}
|
|
189
|
+
if (selectedCall.conversationId !== conversationId) {
|
|
190
|
+
// Treat a cross-conversation callId as a bad request rather than
|
|
191
|
+
// silently filtering against the wrong conversation. The frontend
|
|
192
|
+
// always pairs (conversationId, callId) from the same rail, so a
|
|
193
|
+
// mismatch is a real client bug — surface it.
|
|
194
|
+
throw new BadRequestError(
|
|
195
|
+
`LLM call ${callId} does not belong to conversation ${conversationId}`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Resolve the window floor — the most recent non-`compactionAgent`
|
|
200
|
+
// call before the selected one. `null` means the selected call is the
|
|
201
|
+
// first real call in the conversation, so every preceding compaction
|
|
202
|
+
// is in scope. The store function applies the strict-`>` predicate
|
|
203
|
+
// (or drops it entirely on null), so the selected call's own
|
|
204
|
+
// `createdAt` is the only ceiling we pass.
|
|
205
|
+
const afterCreatedAt = await source.getPreviousNonCompactionCallCreatedAt(
|
|
206
|
+
conversationId,
|
|
207
|
+
selectedCall.createdAt,
|
|
208
|
+
);
|
|
209
|
+
const logs = await source.getCompactionLogsBetween(
|
|
210
|
+
conversationId,
|
|
211
|
+
afterCreatedAt,
|
|
212
|
+
selectedCall.createdAt,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
conversationId,
|
|
217
|
+
events: logs.map(projectLogRowToCompactionTrailEvent),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// Route registration
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
export const ROUTES: RouteDefinition[] = [
|
|
226
|
+
{
|
|
227
|
+
operationId: "conversations_compaction_trail_get",
|
|
228
|
+
endpoint: "conversations/:id/compaction",
|
|
229
|
+
method: "GET",
|
|
230
|
+
policyKey: "conversations/compaction",
|
|
231
|
+
summary: "Get the compaction trail leading up to an LLM call",
|
|
232
|
+
description:
|
|
233
|
+
"Return the chronological list of compaction events that ran in this conversation in the open window between the previous non-`compactionAgent` LLM call and the call identified by `callId`. Projected from `llm_request_logs` rows where `call_site = \"compactionAgent\"`. When the selected call is the first real call in the conversation, every preceding compaction is in scope. Drives the Inspector's Compaction tab.",
|
|
234
|
+
tags: ["conversations"],
|
|
235
|
+
pathParams: [
|
|
236
|
+
{
|
|
237
|
+
name: "id",
|
|
238
|
+
description: "Internal conversation identifier.",
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
queryParams: [
|
|
242
|
+
{
|
|
243
|
+
name: "callId",
|
|
244
|
+
required: true,
|
|
245
|
+
schema: { type: "string" },
|
|
246
|
+
description:
|
|
247
|
+
"ID of the selected LLM call from the rail. Defines the chronological cutoff for the trail.",
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
responseBody: compactionTrailResponseSchema,
|
|
251
|
+
additionalResponses: {
|
|
252
|
+
"400": {
|
|
253
|
+
description:
|
|
254
|
+
"Returned when the callId is missing or refers to a call in a different conversation.",
|
|
255
|
+
},
|
|
256
|
+
"404": {
|
|
257
|
+
description:
|
|
258
|
+
"Returned when the conversation or the referenced LLM call does not exist.",
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
handler: handleGetCompactionTrail,
|
|
262
|
+
},
|
|
263
|
+
];
|