@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
|
@@ -2,87 +2,25 @@
|
|
|
2
2
|
* Suggested prompt producer for the Home feed.
|
|
3
3
|
*
|
|
4
4
|
* Returns an array of `SuggestedPrompt` items shown at the top of the
|
|
5
|
-
* Home page as conversation starters
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Computed inline (read-only, safe for GET).
|
|
10
|
-
* - **Assistant-generated** — contextual suggestions from the LLM
|
|
11
|
-
* based on what's relevant to the user. Read from an in-memory
|
|
12
|
-
* cache in the GET path; generation runs in the background via
|
|
13
|
-
* `refreshAssistantSuggestedPrompts`.
|
|
5
|
+
* Home page as conversation starters. All prompts are generated by the
|
|
6
|
+
* assistant based on the user's connected services and context —
|
|
7
|
+
* read from an in-memory cache in the GET path; generation runs in
|
|
8
|
+
* the background via `refreshAssistantSuggestedPrompts`.
|
|
14
9
|
*/
|
|
15
10
|
|
|
16
11
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
17
12
|
import { getConfig } from "../config/loader.js";
|
|
18
|
-
import { listProviders } from "../oauth/oauth-store.js";
|
|
19
13
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
20
14
|
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
21
15
|
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
22
16
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
23
17
|
import { runBtwSidechain } from "../runtime/btw-sidechain.js";
|
|
24
|
-
import {
|
|
18
|
+
import { formatIntegrationSummary } from "../schedule/integration-status.js";
|
|
25
19
|
import { getLogger } from "../util/logger.js";
|
|
26
20
|
import type { SuggestedPrompt } from "./feed-types.js";
|
|
27
21
|
|
|
28
22
|
const log = getLogger("suggested-prompts");
|
|
29
23
|
|
|
30
|
-
/**
|
|
31
|
-
* Map of provider keys to their suggested-prompt metadata. Only providers
|
|
32
|
-
* listed here produce deterministic "Connect X" prompts when disconnected.
|
|
33
|
-
* The icon values are VIcon case names rendered by the macOS client.
|
|
34
|
-
*/
|
|
35
|
-
interface PromptEntry {
|
|
36
|
-
label: string;
|
|
37
|
-
prompt: string;
|
|
38
|
-
icon: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const CONNECT_PROMPT_META: Record<
|
|
42
|
-
string,
|
|
43
|
-
PromptEntry & { connectedPrompts?: PromptEntry[] }
|
|
44
|
-
> = {
|
|
45
|
-
google: {
|
|
46
|
-
label: "Connect Gmail",
|
|
47
|
-
prompt: "Help me connect my Gmail account",
|
|
48
|
-
icon: "mail",
|
|
49
|
-
connectedPrompts: [
|
|
50
|
-
{
|
|
51
|
-
label: "Triage my inbox",
|
|
52
|
-
prompt:
|
|
53
|
-
"Help me triage my inbox — summarize what's unread and flag anything that needs a reply",
|
|
54
|
-
icon: "mail",
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
label: "Summarize today's emails",
|
|
58
|
-
prompt:
|
|
59
|
-
"Summarize the emails I received today and highlight anything important",
|
|
60
|
-
icon: "mail",
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
slack: {
|
|
65
|
-
label: "Connect Slack",
|
|
66
|
-
prompt: "Help me connect my Slack workspace",
|
|
67
|
-
icon: "hash",
|
|
68
|
-
},
|
|
69
|
-
notion: {
|
|
70
|
-
label: "Connect Notion",
|
|
71
|
-
prompt: "Help me connect my Notion workspace",
|
|
72
|
-
icon: "fileText",
|
|
73
|
-
},
|
|
74
|
-
linear: {
|
|
75
|
-
label: "Connect Linear",
|
|
76
|
-
prompt: "Help me connect my Linear workspace",
|
|
77
|
-
icon: "clipboardList",
|
|
78
|
-
},
|
|
79
|
-
github: {
|
|
80
|
-
label: "Connect GitHub",
|
|
81
|
-
prompt: "Help me connect my GitHub account",
|
|
82
|
-
icon: "terminal",
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
|
|
86
24
|
const LLM_SUGGESTIONS_TIMEOUT_MS = 5_000;
|
|
87
25
|
const LLM_CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
88
26
|
|
|
@@ -94,37 +32,23 @@ let cachedLLMPrompts: SuggestedPrompt[] = [];
|
|
|
94
32
|
let cachedLLMPromptsAt = 0;
|
|
95
33
|
|
|
96
34
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
35
|
+
* Return cached assistant-generated prompts. No LLM calls happen in
|
|
36
|
+
* this path — safe for GET. Returns an empty array until the first
|
|
37
|
+
* background refresh populates the cache.
|
|
100
38
|
*/
|
|
101
39
|
export async function getSuggestedPrompts(): Promise<SuggestedPrompt[]> {
|
|
102
|
-
const prompts: SuggestedPrompt[] = [];
|
|
103
|
-
|
|
104
|
-
let deterministicPrompts: SuggestedPrompt[] = [];
|
|
105
|
-
try {
|
|
106
|
-
deterministicPrompts = await getDeterministicPrompts();
|
|
107
|
-
prompts.push(...deterministicPrompts);
|
|
108
|
-
} catch (err) {
|
|
109
|
-
log.warn({ err }, "Failed to compute deterministic suggested prompts");
|
|
110
|
-
}
|
|
111
|
-
|
|
112
40
|
if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
|
|
113
|
-
|
|
41
|
+
return [...cachedLLMPrompts];
|
|
114
42
|
}
|
|
115
|
-
|
|
116
|
-
return prompts;
|
|
43
|
+
return [];
|
|
117
44
|
}
|
|
118
45
|
|
|
119
46
|
/**
|
|
120
|
-
* Drops the in-memory
|
|
121
|
-
*
|
|
122
|
-
* a follow-up background refresh repopulates the LLM half).
|
|
47
|
+
* Drops the in-memory suggestion cache so the next background refresh
|
|
48
|
+
* regenerates prompts with current integration state.
|
|
123
49
|
*
|
|
124
|
-
* Called from OAuth connect/disconnect paths so
|
|
125
|
-
*
|
|
126
|
-
* 30-minute TTL would otherwise pin a stale suggestion until the next
|
|
127
|
-
* periodic refresh.
|
|
50
|
+
* Called from OAuth connect/disconnect paths so suggestions reflect the
|
|
51
|
+
* new state within one reload instead of waiting for the 30-minute TTL.
|
|
128
52
|
*/
|
|
129
53
|
export function invalidateAssistantSuggestedPromptsCache(): void {
|
|
130
54
|
cachedLLMPrompts = [];
|
|
@@ -156,8 +80,7 @@ export async function refreshAssistantSuggestedPrompts(): Promise<void> {
|
|
|
156
80
|
}
|
|
157
81
|
|
|
158
82
|
try {
|
|
159
|
-
const
|
|
160
|
-
const llmPrompts = await generateAssistantPrompts(deterministicPrompts);
|
|
83
|
+
const llmPrompts = await generateAssistantPrompts();
|
|
161
84
|
cachedLLMPrompts = llmPrompts;
|
|
162
85
|
cachedLLMPromptsAt = Date.now();
|
|
163
86
|
} catch (err) {
|
|
@@ -165,49 +88,6 @@ export async function refreshAssistantSuggestedPrompts(): Promise<void> {
|
|
|
165
88
|
}
|
|
166
89
|
}
|
|
167
90
|
|
|
168
|
-
/**
|
|
169
|
-
* Check which well-known OAuth providers are not connected and return
|
|
170
|
-
* a "Connect X" prompt for each. For connected providers that have
|
|
171
|
-
* `connectedPrompts`, return those instead so users discover ongoing
|
|
172
|
-
* management capabilities.
|
|
173
|
-
*/
|
|
174
|
-
async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
|
|
175
|
-
const providers = listProviders();
|
|
176
|
-
const prompts: SuggestedPrompt[] = [];
|
|
177
|
-
|
|
178
|
-
for (const provider of providers) {
|
|
179
|
-
const meta = CONNECT_PROMPT_META[provider.provider];
|
|
180
|
-
if (!meta) continue;
|
|
181
|
-
|
|
182
|
-
const connected = await isOAuthProviderConnected(provider.provider);
|
|
183
|
-
|
|
184
|
-
if (!connected) {
|
|
185
|
-
prompts.push({
|
|
186
|
-
id: `connect-${provider.provider}`,
|
|
187
|
-
label: meta.label,
|
|
188
|
-
icon: meta.icon,
|
|
189
|
-
prompt: meta.prompt,
|
|
190
|
-
source: "deterministic",
|
|
191
|
-
});
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (meta.connectedPrompts) {
|
|
196
|
-
for (const cp of meta.connectedPrompts) {
|
|
197
|
-
prompts.push({
|
|
198
|
-
id: `manage-${provider.provider}-${cp.label.toLowerCase().replace(/\s+/g, "-")}`,
|
|
199
|
-
label: cp.label,
|
|
200
|
-
icon: cp.icon,
|
|
201
|
-
prompt: cp.prompt,
|
|
202
|
-
source: "deterministic",
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return prompts;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
91
|
// ---------------------------------------------------------------------------
|
|
212
92
|
// LLM-generated suggestions
|
|
213
93
|
// ---------------------------------------------------------------------------
|
|
@@ -220,11 +100,9 @@ interface LLMSuggestion {
|
|
|
220
100
|
/**
|
|
221
101
|
* Ask the LLM to generate contextual conversation-starter suggestions
|
|
222
102
|
* based on the assistant's persona and the user's connected services.
|
|
223
|
-
* Returns an empty array on failure
|
|
103
|
+
* Returns an empty array on failure.
|
|
224
104
|
*/
|
|
225
|
-
async function generateAssistantPrompts(
|
|
226
|
-
deterministicPrompts: SuggestedPrompt[],
|
|
227
|
-
): Promise<SuggestedPrompt[]> {
|
|
105
|
+
async function generateAssistantPrompts(): Promise<SuggestedPrompt[]> {
|
|
228
106
|
const config = getConfig();
|
|
229
107
|
const resolved = resolveCallSiteConfig("homeSuggestedPrompts", config.llm);
|
|
230
108
|
|
|
@@ -238,17 +116,21 @@ async function generateAssistantPrompts(
|
|
|
238
116
|
excludeCustomPrefix: true,
|
|
239
117
|
});
|
|
240
118
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
119
|
+
let integrationContext = "";
|
|
120
|
+
try {
|
|
121
|
+
integrationContext = `\nConnected integrations: ${await formatIntegrationSummary()}`;
|
|
122
|
+
} catch {
|
|
123
|
+
// Best-effort — continue without integration info
|
|
124
|
+
}
|
|
245
125
|
|
|
246
126
|
const result = await runBtwSidechain({
|
|
247
127
|
content:
|
|
248
128
|
"Suggest 2-3 short, actionable conversation starters for the home page. " +
|
|
249
129
|
"Each should be something specific and helpful you can do for the user right now. " +
|
|
250
|
-
|
|
251
|
-
|
|
130
|
+
"Focus on things the user's connected services enable — don't suggest connecting services they already have. " +
|
|
131
|
+
"You may suggest connecting a service only if it's not yet connected and would be genuinely useful." +
|
|
132
|
+
integrationContext +
|
|
133
|
+
' Return ONLY a JSON array of objects with "label" (max 5 words) and "prompt" (the full message to send). ' +
|
|
252
134
|
"No markdown fences, no explanation.",
|
|
253
135
|
provider,
|
|
254
136
|
systemPrompt,
|
|
@@ -37,6 +37,7 @@ mock.module("../../runtime/agent-wake.js", () => ({
|
|
|
37
37
|
|
|
38
38
|
mock.module("../../memory/conversation-crud.js", () => ({
|
|
39
39
|
getConversation: (id: string) => ({ id, createdAt: Date.now() }),
|
|
40
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
40
41
|
}));
|
|
41
42
|
|
|
42
43
|
// ---------------------------------------------------------------------------
|
|
@@ -108,7 +108,10 @@ describe("ipcGetFeatureFlags", () => {
|
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
test("returns empty record when IPC returns undefined", async () => {
|
|
111
|
-
//
|
|
111
|
+
// Explicitly suppress the mock's default `get_feature_flags` sentinel
|
|
112
|
+
// (which exists to short-circuit `initFeatureFlagOverrides()`'s retry
|
|
113
|
+
// loop) so this test exercises the underlying-undefined path.
|
|
114
|
+
mockGatewayIpc(null, { results: { get_feature_flags: undefined } });
|
|
112
115
|
const flags = await ipcGetFeatureFlags();
|
|
113
116
|
expect(flags).toEqual({});
|
|
114
117
|
});
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
__clearExternalToolProvidersForTesting,
|
|
20
20
|
__clearRegistryForTesting,
|
|
21
21
|
getTool,
|
|
22
|
+
getToolOwner,
|
|
22
23
|
} from "../../../tools/registry.js";
|
|
23
24
|
import {
|
|
24
25
|
__getActiveSessionCountForTesting,
|
|
@@ -55,7 +56,12 @@ afterEach(() => {
|
|
|
55
56
|
|
|
56
57
|
describe("host.registries.register_tools", () => {
|
|
57
58
|
test("installs proxy tools into the daemon's external tool registry", async () => {
|
|
59
|
+
// `skillId` lives at the top of the params object (one frame = one
|
|
60
|
+
// skill's batch). The per-tool manifest schema no longer carries an
|
|
61
|
+
// `owner` field — ownership flows in through this top-level key and
|
|
62
|
+
// is recorded in the registry's `ownersByName` map.
|
|
58
63
|
const result = (await registerToolsRoute.handler({
|
|
64
|
+
skillId: "demo-skill",
|
|
59
65
|
tools: [
|
|
60
66
|
{
|
|
61
67
|
name: "skill_demo_tool",
|
|
@@ -64,7 +70,6 @@ describe("host.registries.register_tools", () => {
|
|
|
64
70
|
defaultRiskLevel: "low",
|
|
65
71
|
category: "skill",
|
|
66
72
|
executionTarget: "sandbox",
|
|
67
|
-
ownerSkillId: "demo-skill",
|
|
68
73
|
},
|
|
69
74
|
],
|
|
70
75
|
})) as { registered: string[] };
|
|
@@ -72,13 +77,17 @@ describe("host.registries.register_tools", () => {
|
|
|
72
77
|
expect(result.registered).toEqual(["skill_demo_tool"]);
|
|
73
78
|
const installed = getTool("skill_demo_tool");
|
|
74
79
|
expect(installed).toBeDefined();
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
expect(
|
|
80
|
+
// Ownership lives on the registry — getToolOwner is the single source of
|
|
81
|
+
// truth. The Tool object itself no longer carries the kind.
|
|
82
|
+
expect(getToolOwner("skill_demo_tool")).toEqual({
|
|
83
|
+
kind: "skill",
|
|
84
|
+
id: "demo-skill",
|
|
85
|
+
});
|
|
78
86
|
});
|
|
79
87
|
|
|
80
88
|
test("proxy execute throws when no supervisor is attached", async () => {
|
|
81
89
|
await registerToolsRoute.handler({
|
|
90
|
+
skillId: "stub-skill",
|
|
82
91
|
tools: [
|
|
83
92
|
{
|
|
84
93
|
name: "skill_stub_tool",
|
|
@@ -86,7 +95,6 @@ describe("host.registries.register_tools", () => {
|
|
|
86
95
|
input_schema: { type: "object" },
|
|
87
96
|
defaultRiskLevel: "medium",
|
|
88
97
|
category: "skill",
|
|
89
|
-
ownerSkillId: "stub-skill",
|
|
90
98
|
},
|
|
91
99
|
],
|
|
92
100
|
});
|
|
@@ -106,16 +114,37 @@ describe("host.registries.register_tools", () => {
|
|
|
106
114
|
});
|
|
107
115
|
|
|
108
116
|
test("rejects empty tool list", async () => {
|
|
109
|
-
await expect(
|
|
117
|
+
await expect(
|
|
118
|
+
registerToolsRoute.handler({ skillId: "any-skill", tools: [] }),
|
|
119
|
+
).rejects.toThrow();
|
|
110
120
|
});
|
|
111
121
|
|
|
112
122
|
test("rejects missing required fields", async () => {
|
|
113
123
|
await expect(
|
|
114
124
|
registerToolsRoute.handler({
|
|
125
|
+
skillId: "any-skill",
|
|
115
126
|
tools: [{ name: "missing_rest" }],
|
|
116
127
|
}),
|
|
117
128
|
).rejects.toThrow();
|
|
118
129
|
});
|
|
130
|
+
|
|
131
|
+
test("rejects missing skillId", async () => {
|
|
132
|
+
// skillId is the only place ownership flows in over IPC — without it
|
|
133
|
+
// the registry can't claim the tools, so the handler must reject.
|
|
134
|
+
await expect(
|
|
135
|
+
registerToolsRoute.handler({
|
|
136
|
+
tools: [
|
|
137
|
+
{
|
|
138
|
+
name: "skill_orphan_tool",
|
|
139
|
+
description: "no owner",
|
|
140
|
+
input_schema: { type: "object" },
|
|
141
|
+
defaultRiskLevel: "low",
|
|
142
|
+
category: "skill",
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
}),
|
|
146
|
+
).rejects.toThrow();
|
|
147
|
+
});
|
|
119
148
|
});
|
|
120
149
|
|
|
121
150
|
// ---------------------------------------------------------------------------
|
|
@@ -302,6 +331,7 @@ describe("lazy-external short-circuit", () => {
|
|
|
302
331
|
|
|
303
332
|
const result = (await registerToolsRoute.handler(
|
|
304
333
|
{
|
|
334
|
+
skillId: "demo-skill",
|
|
305
335
|
tools: [
|
|
306
336
|
{
|
|
307
337
|
name: "skill_demo_tool",
|
|
@@ -309,7 +339,6 @@ describe("lazy-external short-circuit", () => {
|
|
|
309
339
|
input_schema: {},
|
|
310
340
|
defaultRiskLevel: "low",
|
|
311
341
|
category: "skill",
|
|
312
|
-
ownerSkillId: "demo-skill",
|
|
313
342
|
},
|
|
314
343
|
],
|
|
315
344
|
},
|
|
@@ -17,13 +17,14 @@ import type { SkillIpcRoute } from "../skill-ipc-types.js";
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Shape mirrors the daemon's `addMessage()` positional signature:
|
|
20
|
-
* `(conversationId, role, content, metadata?, opts?)`.
|
|
21
|
-
*
|
|
20
|
+
* `(conversationId, role, content, metadata?, opts?)`. `role` is
|
|
21
|
+
* constrained to the `MessageRole` union. Metadata is a free-form
|
|
22
|
+
* record (validated downstream by `messageMetadataSchema` with a
|
|
22
23
|
* warn-and-store fallback). Only `skipIndexing` is recognised in `opts`.
|
|
23
24
|
*/
|
|
24
25
|
const MemoryAddMessageParams = z.object({
|
|
25
26
|
conversationId: z.string().min(1),
|
|
26
|
-
role: z.
|
|
27
|
+
role: z.enum(["user", "assistant", "system"]),
|
|
27
28
|
content: z.string(),
|
|
28
29
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
29
30
|
opts: z
|
|
@@ -48,18 +48,19 @@ const ToolManifestSchema = z.object({
|
|
|
48
48
|
defaultRiskLevel: z.enum(["low", "medium", "high"]),
|
|
49
49
|
category: z.string().min(1),
|
|
50
50
|
executionTarget: z.enum(["sandbox", "host"]).optional(),
|
|
51
|
-
executionMode: z.enum(["local", "proxy"]).optional(),
|
|
52
|
-
// Required so disconnect can decrement the tool-registry refcount: a
|
|
53
|
-
// tool registered without an owner has no ref-counted entry to drop and
|
|
54
|
-
// would leak into the global registry on socket close.
|
|
55
|
-
ownerSkillId: z.string().min(1),
|
|
56
|
-
ownerSkillBundled: z.boolean().optional(),
|
|
57
|
-
ownerSkillVersionHash: z.string().optional(),
|
|
58
51
|
});
|
|
59
52
|
|
|
60
53
|
export type ToolManifest = z.infer<typeof ToolManifestSchema>;
|
|
61
54
|
|
|
55
|
+
// `skillId` lives at the params level rather than per-tool: a single
|
|
56
|
+
// `register_tools` IPC frame is always one skill's batch, ownership flows
|
|
57
|
+
// through `registerSkillTools(skillId, tools)` into the registry's
|
|
58
|
+
// `ownersByName` map, and the tools themselves stay free of owner
|
|
59
|
+
// metadata so callers cannot spoof ownership by forging a field on the
|
|
60
|
+
// manifest. Only skill-owned tools cross IPC — plugin and MCP tools live
|
|
61
|
+
// in-process on the assistant side.
|
|
62
62
|
const RegisterToolsParams = z.object({
|
|
63
|
+
skillId: z.string().min(1),
|
|
63
64
|
tools: z.array(ToolManifestSchema).min(1),
|
|
64
65
|
});
|
|
65
66
|
|
|
@@ -187,16 +188,10 @@ function buildProxyTool(manifest: ToolManifest): Tool {
|
|
|
187
188
|
input_schema: manifest.input_schema as object,
|
|
188
189
|
category: manifest.category,
|
|
189
190
|
defaultRiskLevel: manifest.defaultRiskLevel as RiskLevel,
|
|
190
|
-
executionMode: manifest.executionMode ?? "proxy",
|
|
191
191
|
executionTarget: resolveExecutionTarget({
|
|
192
192
|
name: manifest.name,
|
|
193
193
|
executionTarget: manifest.executionTarget as ExecutionTarget | undefined,
|
|
194
|
-
executionMode: manifest.executionMode ?? "proxy",
|
|
195
194
|
}),
|
|
196
|
-
origin: "skill",
|
|
197
|
-
ownerSkillId: manifest.ownerSkillId,
|
|
198
|
-
ownerSkillBundled: manifest.ownerSkillBundled,
|
|
199
|
-
ownerSkillVersionHash: manifest.ownerSkillVersionHash,
|
|
200
195
|
execute: async () => {
|
|
201
196
|
// Only reached when no supervisor is attached (tests/boot race);
|
|
202
197
|
// the supervisor short-circuit above replaces this with the
|
|
@@ -214,7 +209,7 @@ async function handleRegisterTools(
|
|
|
214
209
|
params: Record<string, unknown> | undefined,
|
|
215
210
|
connection?: unknown,
|
|
216
211
|
): Promise<{ registered: string[] }> {
|
|
217
|
-
const { tools } = RegisterToolsParams.parse(params);
|
|
212
|
+
const { skillId, tools } = RegisterToolsParams.parse(params);
|
|
218
213
|
const conn = connection as SkillIpcConnection | undefined;
|
|
219
214
|
|
|
220
215
|
// Supervisor short-circuit: when a supervisor is registered, the
|
|
@@ -226,7 +221,11 @@ async function handleRegisterTools(
|
|
|
226
221
|
if (sessionSupervisor) {
|
|
227
222
|
if (conn) sessionSupervisor.setActiveConnection(conn);
|
|
228
223
|
log.info(
|
|
229
|
-
{
|
|
224
|
+
{
|
|
225
|
+
count: tools.length,
|
|
226
|
+
names: tools.map((t) => t.name),
|
|
227
|
+
ownerSkillId: skillId,
|
|
228
|
+
},
|
|
230
229
|
"Supervisor active: skipping in-memory tool re-registration; manifest proxies serve dispatches",
|
|
231
230
|
);
|
|
232
231
|
return { registered: tools.map((t) => t.name) };
|
|
@@ -236,23 +235,23 @@ async function handleRegisterTools(
|
|
|
236
235
|
// `registerExternalTools` is only consumed inside `initializeTools()` at
|
|
237
236
|
// daemon boot; IPC children connect after boot, so route through
|
|
238
237
|
// `registerSkillTools` into the live registry the agent-loop reads from.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
for (const skillId of ownerIds) {
|
|
250
|
-
conn.addSkillToolsOwner(skillId);
|
|
251
|
-
}
|
|
238
|
+
// Owner is stamped registry-side from `skillId`; the proxy `Tool` objects
|
|
239
|
+
// carry no owner field.
|
|
240
|
+
const accepted = registerSkillTools(skillId, proxies);
|
|
241
|
+
|
|
242
|
+
// `registerSkillTools` increments the registry refcount once per call;
|
|
243
|
+
// mirror that on the connection so disconnect issues exactly one matching
|
|
244
|
+
// decrement.
|
|
245
|
+
if (conn && accepted.length > 0) {
|
|
246
|
+
conn.addSkillToolsOwner(skillId);
|
|
252
247
|
}
|
|
253
248
|
|
|
254
249
|
log.info(
|
|
255
|
-
{
|
|
250
|
+
{
|
|
251
|
+
count: accepted.length,
|
|
252
|
+
names: accepted.map((t) => t.name),
|
|
253
|
+
ownerSkillId: skillId,
|
|
254
|
+
},
|
|
256
255
|
"Registered skill proxy tools via IPC",
|
|
257
256
|
);
|
|
258
257
|
return { registered: accepted.map((t) => t.name) };
|
|
@@ -57,6 +57,7 @@ mock.module("../../runtime/actor-trust-resolver.js", () => ({
|
|
|
57
57
|
// retrospective and auto-analysis paths fall through to the enqueue.
|
|
58
58
|
mock.module("../conversation-crud.js", () => ({
|
|
59
59
|
getConversationSource: () => null,
|
|
60
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
60
61
|
}));
|
|
61
62
|
mock.module("../auto-analysis-guard.js", () => ({
|
|
62
63
|
isAutoAnalysisConversation: () => false,
|
|
@@ -34,11 +34,9 @@ import {
|
|
|
34
34
|
|
|
35
35
|
import { eq } from "drizzle-orm";
|
|
36
36
|
|
|
37
|
-
import {
|
|
37
|
+
import { createMockLoggerModule } from "../../__tests__/helpers/mock-logger.js";
|
|
38
38
|
|
|
39
|
-
mock.module("../../util/logger.js", () => (
|
|
40
|
-
getLogger: () => makeMockLogger(),
|
|
41
|
-
}));
|
|
39
|
+
mock.module("../../util/logger.js", () => createMockLoggerModule());
|
|
42
40
|
|
|
43
41
|
// Workspace pin must precede the `db` import below — the DB singleton
|
|
44
42
|
// resolves its path at first call, so we need the env var set before
|
|
@@ -279,10 +277,33 @@ describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
|
|
|
279
277
|
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
280
278
|
|
|
281
279
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
282
|
-
// Checkpoint refreshed so the
|
|
280
|
+
// Checkpoint refreshed so the time-based branch doesn't re-fire.
|
|
283
281
|
expect(getMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY)).toBe(String(now));
|
|
284
282
|
});
|
|
285
283
|
|
|
284
|
+
test("does not re-fire on every tick while buffer stays over threshold", () => {
|
|
285
|
+
const config = buildConfig({
|
|
286
|
+
v2Enabled: true,
|
|
287
|
+
intervalHours: 1,
|
|
288
|
+
maxBufferLines: 5,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const now = Date.now();
|
|
292
|
+
// Recent checkpoint so the time-based branch never fires across ticks —
|
|
293
|
+
// the only thing that could re-enqueue is the size branch.
|
|
294
|
+
setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
|
|
295
|
+
writeBuffer(10);
|
|
296
|
+
|
|
297
|
+
// Simulate several worker ticks with the buffer still over threshold and
|
|
298
|
+
// the first-tick job still pending (nothing has drained it yet).
|
|
299
|
+
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
300
|
+
maybeEnqueueGraphMaintenanceJobs(config, now + 1_000);
|
|
301
|
+
maybeEnqueueGraphMaintenanceJobs(config, now + 2_000);
|
|
302
|
+
|
|
303
|
+
// A pending consolidate job dedupes the later ticks — only one enqueue.
|
|
304
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
305
|
+
});
|
|
306
|
+
|
|
286
307
|
test("does not enqueue when buffer is under the threshold", () => {
|
|
287
308
|
const config = buildConfig({
|
|
288
309
|
v2Enabled: true,
|
|
@@ -144,6 +144,7 @@ mock.module("../conversation-crud.js", () => ({
|
|
|
144
144
|
deleteConversation: (id: string) => {
|
|
145
145
|
deletedConversationIds.push(id);
|
|
146
146
|
},
|
|
147
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
147
148
|
}));
|
|
148
149
|
|
|
149
150
|
mock.module("../../config/assistant-feature-flags.js", () => ({
|
|
@@ -108,6 +108,7 @@ mock.module("../conversation-crud.js", () => ({
|
|
|
108
108
|
deletedIds.push(id);
|
|
109
109
|
mockConversations = mockConversations.filter((c) => c.id !== id);
|
|
110
110
|
},
|
|
111
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
111
112
|
}));
|
|
112
113
|
|
|
113
114
|
import { sweepOrphanMemoryRetrospectiveConversations } from "../memory-retrospective-startup-cleanup.js";
|
|
@@ -187,4 +187,35 @@ describe("memory-v2-activation-log-store", () => {
|
|
|
187
187
|
expect(byTurn.get(2)!.messageId).toBe("msg-a");
|
|
188
188
|
expect(byTurn.get(3)!.messageId).toBe("msg-b");
|
|
189
189
|
});
|
|
190
|
+
|
|
191
|
+
test("backfill skips v3_shadow rows, leaving their messageId null", () => {
|
|
192
|
+
const conversationId = "conv-shadow-backfill";
|
|
193
|
+
|
|
194
|
+
// A live router row (null messageId) and a detached v3_shadow row (null
|
|
195
|
+
// messageId) coexist in the same conversation.
|
|
196
|
+
recordMemoryV2ActivationLog({
|
|
197
|
+
conversationId,
|
|
198
|
+
turn: 5,
|
|
199
|
+
mode: "router",
|
|
200
|
+
concepts: sampleConcepts,
|
|
201
|
+
config: sampleConfig,
|
|
202
|
+
});
|
|
203
|
+
recordMemoryV2ActivationLog({
|
|
204
|
+
conversationId,
|
|
205
|
+
turn: 5,
|
|
206
|
+
mode: "v3_shadow",
|
|
207
|
+
concepts: sampleConcepts,
|
|
208
|
+
config: sampleConfig,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
backfillMemoryV2ActivationMessageId(conversationId, "msg-live");
|
|
212
|
+
|
|
213
|
+
const db = getDb();
|
|
214
|
+
const rows = db.select().from(memoryV2ActivationLogs).all();
|
|
215
|
+
const byMode = new Map(rows.map((r) => [r.mode, r]));
|
|
216
|
+
// The live router row got stamped; the shadow row stayed null (not
|
|
217
|
+
// mis-attributed to the live message).
|
|
218
|
+
expect(byMode.get("router")!.messageId).toBe("msg-live");
|
|
219
|
+
expect(byMode.get("v3_shadow")!.messageId).toBeNull();
|
|
220
|
+
});
|
|
190
221
|
});
|