@vellumai/assistant 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -0
- package/Dockerfile +5 -4
- package/README.md +2 -2
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4847 -1698
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +21 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +23 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +2 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +23 -4
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +76 -14
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +127 -97
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +46 -5
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +24 -14
- package/src/daemon/conversation.ts +48 -9
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +42 -43
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +9 -2
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +40 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +148 -127
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +76 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +44 -5
- package/src/memory/indexer.ts +17 -0
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
- package/src/memory/jobs/embed-concept-page.ts +45 -9
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +52 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -4
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +628 -10
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +440 -109
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +100 -87
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +19 -3
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +12 -4
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +303 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +334 -86
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/memory/register.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +13 -5
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +22 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Home-feed side effect for the notification pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Writes a `FeedItem` into the home activity feed when a notification
|
|
5
|
+
* signal originates from a non-interactive (background or scheduled)
|
|
6
|
+
* conversation, or carries the `isAsyncBackground` attention hint.
|
|
7
|
+
*
|
|
8
|
+
* Producer flows like the scheduler, watchers, and background activity
|
|
9
|
+
* jobs already emit through `emitNotificationSignal()` — this helper
|
|
10
|
+
* mirrors the high-signal subset of that traffic into the home feed so
|
|
11
|
+
* the macOS Home page surfaces them alongside other activity.
|
|
12
|
+
*/
|
|
13
|
+
import {
|
|
14
|
+
type FeedItem,
|
|
15
|
+
feedItemSchema,
|
|
16
|
+
type FeedItemUrgency,
|
|
17
|
+
} from "../home/feed-types.js";
|
|
18
|
+
import { appendFeedItem } from "../home/feed-writer.js";
|
|
19
|
+
import { getConversation } from "../memory/conversation-crud.js";
|
|
20
|
+
import { isBackgroundConversationType } from "../memory/conversation-types.js";
|
|
21
|
+
import { getLogger } from "../util/logger.js";
|
|
22
|
+
import type { NotificationSignal } from "./signal.js";
|
|
23
|
+
import type {
|
|
24
|
+
NotificationDecision,
|
|
25
|
+
NotificationDeliveryResult,
|
|
26
|
+
} from "./types.js";
|
|
27
|
+
|
|
28
|
+
const log = getLogger("home-feed-side-effect");
|
|
29
|
+
|
|
30
|
+
const FEED_ITEM_URGENCIES: ReadonlySet<string> = new Set<FeedItemUrgency>([
|
|
31
|
+
"low",
|
|
32
|
+
"medium",
|
|
33
|
+
"high",
|
|
34
|
+
"critical",
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Append a `FeedItem` for the given notification signal when the
|
|
39
|
+
* filter criteria pass.
|
|
40
|
+
*
|
|
41
|
+
* Returns the persisted `FeedItem`, or `null` if the signal does not
|
|
42
|
+
* qualify for home-feed mirroring (non-background origin AND no
|
|
43
|
+
* `isAsyncBackground` hint) or if schema validation fails.
|
|
44
|
+
*/
|
|
45
|
+
export async function writeHomeFeedItemForSignal(
|
|
46
|
+
signal: NotificationSignal,
|
|
47
|
+
decision: NotificationDecision,
|
|
48
|
+
deliveryResults: NotificationDeliveryResult[],
|
|
49
|
+
): Promise<FeedItem | null> {
|
|
50
|
+
if (!shouldMirrorToHomeFeed(signal)) return null;
|
|
51
|
+
|
|
52
|
+
const renderedCopy = decision.renderedCopy.vellum;
|
|
53
|
+
const payloadTitle = readPayloadString(signal.contextPayload, "title");
|
|
54
|
+
const payloadBody = readPayloadString(signal.contextPayload, "body");
|
|
55
|
+
|
|
56
|
+
const conversationId = deliveryResults.find(
|
|
57
|
+
(r) => r.channel === "vellum",
|
|
58
|
+
)?.conversationId;
|
|
59
|
+
const urgency = FEED_ITEM_URGENCIES.has(signal.attentionHints.urgency)
|
|
60
|
+
? (signal.attentionHints.urgency as FeedItemUrgency)
|
|
61
|
+
: undefined;
|
|
62
|
+
const now = new Date().toISOString();
|
|
63
|
+
|
|
64
|
+
const item: FeedItem = {
|
|
65
|
+
id: `notif:${signal.signalId}`,
|
|
66
|
+
type: "notification",
|
|
67
|
+
priority: 50,
|
|
68
|
+
title: renderedCopy?.title ?? payloadTitle ?? signal.sourceEventName,
|
|
69
|
+
summary: renderedCopy?.body ?? payloadBody ?? signal.sourceEventName,
|
|
70
|
+
timestamp: now,
|
|
71
|
+
createdAt: now,
|
|
72
|
+
status: "new",
|
|
73
|
+
...(urgency ? { urgency } : {}),
|
|
74
|
+
...(conversationId ? { conversationId } : {}),
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
feedItemSchema.parse(item);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
log.warn(
|
|
81
|
+
{ err, signalId: signal.signalId },
|
|
82
|
+
"FeedItem failed schema validation; skipping home-feed write",
|
|
83
|
+
);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await appendFeedItem(item);
|
|
88
|
+
return item;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* `sourceContextId` is best-effort — it may not be a conversation id
|
|
93
|
+
* (e.g. scheduler job id, watcher event id), so a lookup failure
|
|
94
|
+
* falls through to "not a background conversation" rather than throwing.
|
|
95
|
+
*/
|
|
96
|
+
function shouldMirrorToHomeFeed(signal: NotificationSignal): boolean {
|
|
97
|
+
if (signal.attentionHints.isAsyncBackground) return true;
|
|
98
|
+
if (!signal.sourceContextId) return false;
|
|
99
|
+
try {
|
|
100
|
+
const row = getConversation(signal.sourceContextId);
|
|
101
|
+
return isBackgroundConversationType(row?.conversationType);
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function readPayloadString(payload: unknown, key: string): string | undefined {
|
|
108
|
+
if (!payload || typeof payload !== "object") return undefined;
|
|
109
|
+
const value = (payload as Record<string, unknown>)[key];
|
|
110
|
+
return typeof value === "string" ? value : undefined;
|
|
111
|
+
}
|
|
@@ -88,6 +88,11 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
|
|
|
88
88
|
description: "Tool requires user confirmation before executing",
|
|
89
89
|
},
|
|
90
90
|
{ id: "activity.complete", description: "Background activity finished" },
|
|
91
|
+
{
|
|
92
|
+
id: "activity.failed",
|
|
93
|
+
description:
|
|
94
|
+
"Background job execution failed (model_provider, exception, or timeout)",
|
|
95
|
+
},
|
|
91
96
|
{
|
|
92
97
|
id: "quick_chat.response_ready",
|
|
93
98
|
description: "Quick chat response ready for review",
|
|
@@ -289,6 +289,17 @@ function buildClassifyRiskParams(
|
|
|
289
289
|
): ClassifyRiskParams {
|
|
290
290
|
// ── Bash/host_bash ──
|
|
291
291
|
if (toolName === "bash" || toolName === "host_bash") {
|
|
292
|
+
// Count credential references attached to this invocation.
|
|
293
|
+
let credentialRefCount: number | undefined;
|
|
294
|
+
if (Array.isArray(input.credential_ids)) {
|
|
295
|
+
const validIds = (input.credential_ids as unknown[]).filter(
|
|
296
|
+
(id) => typeof id === "string" && id.length > 0,
|
|
297
|
+
);
|
|
298
|
+
if (validIds.length > 0) {
|
|
299
|
+
credentialRefCount = validIds.length;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
292
303
|
return {
|
|
293
304
|
tool: toolName,
|
|
294
305
|
command: getStringField(input, "command"),
|
|
@@ -297,6 +308,7 @@ function buildClassifyRiskParams(
|
|
|
297
308
|
isContainerized: getIsContainerized(),
|
|
298
309
|
networkMode:
|
|
299
310
|
typeof input.network_mode === "string" ? input.network_mode : undefined,
|
|
311
|
+
credentialRefCount,
|
|
300
312
|
};
|
|
301
313
|
}
|
|
302
314
|
|
|
@@ -92,4 +92,6 @@ export interface ClassifyRiskParams {
|
|
|
92
92
|
skillMetadata?: SkillMetadata;
|
|
93
93
|
/** Tool registry default risk level for unknown tools. */
|
|
94
94
|
registryDefaultRisk?: string;
|
|
95
|
+
/** Number of credential references attached to this tool invocation. */
|
|
96
|
+
credentialRefCount?: number;
|
|
95
97
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for the `@vellumai/plugin-api` package.
|
|
3
|
+
*
|
|
4
|
+
* Plugin authors import from `"@vellumai/plugin-api"`; this file is what
|
|
5
|
+
* their import lands on (directly via the published npm package, or via a
|
|
6
|
+
* boot-time shim that re-exports from the assistant binary's embedded
|
|
7
|
+
* bundle).
|
|
8
|
+
*
|
|
9
|
+
* Keep this file's surface stable across minor/patch releases. Anything
|
|
10
|
+
* exported here is part of the public contract.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export type { PluginInitContext, PluginShutdownContext } from "./types.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vellumai/plugin-api",
|
|
3
|
+
"version": "0.0.0-source",
|
|
4
|
+
"description": "Public API surface for Vellum assistant plugins. Source-of-truth lives here; the bundled artifact is what gets published to npm and embedded into the assistant binary.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"main": "./index.ts",
|
|
8
|
+
"types": "./index.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./index.ts"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public plugin-API types.
|
|
3
|
+
*
|
|
4
|
+
* This module is the source-of-truth for types that plugin authors depend on.
|
|
5
|
+
* The rest of the assistant imports from here via relative paths
|
|
6
|
+
* (`../plugin-api/types.js`). At publish time, this file's contents are
|
|
7
|
+
* bundled into the `@vellumai/plugin-api` npm package; at runtime in the
|
|
8
|
+
* assistant binary, the same source is reachable to user plugins via a
|
|
9
|
+
* boot-time shim that re-exports from the embedded bundle.
|
|
10
|
+
*
|
|
11
|
+
* Today this module is intentionally narrow — only `PluginInitContext` and
|
|
12
|
+
* `PluginShutdownContext`. Additional public types migrate over in
|
|
13
|
+
* follow-up PRs as the surface stabilizes.
|
|
14
|
+
*
|
|
15
|
+
* Internal-only types (pipeline shapes, middleware, manifest validation,
|
|
16
|
+
* etc.) stay in `assistant/src/plugins/types.ts` until they're ready to
|
|
17
|
+
* become public.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// ─── Init context ────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Context passed to `Plugin.init()` during bootstrap. Carries resolved
|
|
24
|
+
* config/credentials, a pino-compatible logger scoped to the plugin, a
|
|
25
|
+
* per-plugin writable data directory, and the assistant's version metadata.
|
|
26
|
+
*/
|
|
27
|
+
export interface PluginInitContext {
|
|
28
|
+
/** Parsed config for this plugin (may be `unknown` until the manifest validates). */
|
|
29
|
+
config: unknown;
|
|
30
|
+
/** Resolved credential values keyed by the entries of `manifest.requiresCredential`. */
|
|
31
|
+
credentials: Record<string, string>;
|
|
32
|
+
/**
|
|
33
|
+
* Pino-compatible child logger bound to `{ plugin: <name> }`. Untyped here
|
|
34
|
+
* to avoid pulling pino into the types module.
|
|
35
|
+
*/
|
|
36
|
+
logger: unknown;
|
|
37
|
+
/** Absolute path to `<workspaceDir>/plugins-data/<plugin>/` (created by bootstrap). */
|
|
38
|
+
pluginStorageDir: string;
|
|
39
|
+
/** Assistant semver for compatibility checks inside the plugin. */
|
|
40
|
+
assistantVersion: string;
|
|
41
|
+
/** Capability → version-list map (`ASSISTANT_API_VERSIONS`) for defensive runtime checks. */
|
|
42
|
+
apiVersions: Record<string, string[]>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ─── Shutdown context ────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Context passed to the `shutdown` hook during daemon teardown. Kept
|
|
49
|
+
* intentionally narrower than {@link PluginInitContext} — most teardown
|
|
50
|
+
* paths only need to know which assistant version they're shutting
|
|
51
|
+
* down against (e.g. for version-conditional cleanup of state files
|
|
52
|
+
* written by a previous boot).
|
|
53
|
+
*
|
|
54
|
+
* Additional fields may be added as concrete plugin needs surface; the
|
|
55
|
+
* `assistantVersion` field mirrors the init context's so plugins that
|
|
56
|
+
* stash a version stamp at init can compare against the same name on
|
|
57
|
+
* tear-down without keeping their own copy.
|
|
58
|
+
*/
|
|
59
|
+
export interface PluginShutdownContext {
|
|
60
|
+
/** Assistant semver for compatibility checks inside the plugin. */
|
|
61
|
+
assistantVersion: string;
|
|
62
|
+
}
|
|
@@ -251,9 +251,24 @@ const pkbReminderInjector: Injector = {
|
|
|
251
251
|
const mode = inputs.mode ?? "full";
|
|
252
252
|
if (mode !== "full") return null;
|
|
253
253
|
if (!inputs.pkbActive) return null;
|
|
254
|
+
// The `memory-retrospective` feature flag enables a focused background
|
|
255
|
+
// retrospective pass that catches what the in-conversation `remember`
|
|
256
|
+
// calls miss. When that backstop is on, the per-turn pressure to call
|
|
257
|
+
// `remember` softens to a judgment framing. When it's off, the original
|
|
258
|
+
// high-pressure BODY is used so users without the retrospective still
|
|
259
|
+
// get aggressive capture in-conversation.
|
|
260
|
+
let relaxed = false;
|
|
261
|
+
try {
|
|
262
|
+
relaxed = isAssistantFeatureFlagEnabled(
|
|
263
|
+
"memory-retrospective",
|
|
264
|
+
getConfig(),
|
|
265
|
+
);
|
|
266
|
+
} catch {
|
|
267
|
+
// Best-effort — fall back to the default (non-relaxed) BODY.
|
|
268
|
+
}
|
|
254
269
|
const reminder = isPkbInjectionSilencedByV2()
|
|
255
|
-
? buildPkbReminder([])
|
|
256
|
-
: await buildPkbReminderWithHints(inputs);
|
|
270
|
+
? buildPkbReminder([], relaxed)
|
|
271
|
+
: await buildPkbReminderWithHints(inputs, relaxed);
|
|
257
272
|
return {
|
|
258
273
|
id: "pkb-reminder",
|
|
259
274
|
text: reminder,
|
|
@@ -283,6 +298,7 @@ function buildPkbContextBlock(content: string): string {
|
|
|
283
298
|
*/
|
|
284
299
|
async function buildPkbReminderWithHints(
|
|
285
300
|
inputs: TurnInjectionInputs,
|
|
301
|
+
relaxed: boolean,
|
|
286
302
|
): Promise<string> {
|
|
287
303
|
let hints: string[] = [];
|
|
288
304
|
const queryVector = inputs.pkbQueryVector;
|
|
@@ -343,7 +359,7 @@ async function buildPkbReminderWithHints(
|
|
|
343
359
|
hints = [];
|
|
344
360
|
}
|
|
345
361
|
}
|
|
346
|
-
return buildPkbReminder(hints);
|
|
362
|
+
return buildPkbReminder(hints, relaxed);
|
|
347
363
|
}
|
|
348
364
|
|
|
349
365
|
/**
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External plugin loader — builds a {@link Plugin} from a directory and
|
|
3
|
+
* registers it with the runtime.
|
|
4
|
+
*
|
|
5
|
+
* The convention this loader walks is currently **experimental**: surface
|
|
6
|
+
* set, manifest fields, and discovery shape may all change before the
|
|
7
|
+
* framework stabilizes. We keep this module's identifiers harness-neutral
|
|
8
|
+
* ("external") so the stable call path through the harness —
|
|
9
|
+
* `loadUserPlugins → loadExternalPlugin → registerPlugin` — does not
|
|
10
|
+
* need to be renamed when the convention shifts.
|
|
11
|
+
*
|
|
12
|
+
* <pluginDir>/
|
|
13
|
+
* package.json ← manifest.name comes from `name`
|
|
14
|
+
* (npm scope stripped); manifest.requires
|
|
15
|
+
* comes from `vellum.requires` if present
|
|
16
|
+
* hooks/
|
|
17
|
+
* <name>.ts ← default export → plugin.hooks[<name>]
|
|
18
|
+
* (today the runtime invokes "init" at
|
|
19
|
+
* bootstrap and "shutdown" at teardown;
|
|
20
|
+
* other filenames sit in the map for
|
|
21
|
+
* forward compatibility)
|
|
22
|
+
* tools/
|
|
23
|
+
* *.ts ← each file's default export → plugin.tools[]
|
|
24
|
+
* src/ ← internal helpers, ignored by the loader
|
|
25
|
+
*
|
|
26
|
+
* Per-surface, `.js` is preferred over `.ts` (compiled-binary semantics).
|
|
27
|
+
* Missing surface files are silently omitted (the harness treats absent
|
|
28
|
+
* fields as "this plugin contributes nothing here"). Surface files
|
|
29
|
+
* present without a usable default export are a hard failure: the
|
|
30
|
+
* loader logs with attribution and skips the plugin.
|
|
31
|
+
*
|
|
32
|
+
* This function owns the per-plugin isolation contract: it never throws,
|
|
33
|
+
* times out after `importTimeoutMs`, catches any error from the build or
|
|
34
|
+
* `registerPlugin` call, and logs an attributed entry. Callers can
|
|
35
|
+
* `await loadExternalPlugin(...)` in a loop with no per-iteration guard.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
39
|
+
import { readFile } from "node:fs/promises";
|
|
40
|
+
import { join } from "node:path";
|
|
41
|
+
import { pathToFileURL } from "node:url";
|
|
42
|
+
|
|
43
|
+
import { z } from "zod";
|
|
44
|
+
|
|
45
|
+
import { getLogger } from "../util/logger.js";
|
|
46
|
+
import { registerPlugin } from "./registry.js";
|
|
47
|
+
import type {
|
|
48
|
+
Plugin,
|
|
49
|
+
PluginHookFn,
|
|
50
|
+
PluginHooks,
|
|
51
|
+
PluginManifest,
|
|
52
|
+
PluginToolRegistration,
|
|
53
|
+
} from "./types.js";
|
|
54
|
+
|
|
55
|
+
const log = getLogger("external-plugin-loader");
|
|
56
|
+
|
|
57
|
+
/** Default upper bound on how long a single plugin load may take. */
|
|
58
|
+
const DEFAULT_IMPORT_TIMEOUT_MS = 10_000;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Zod schema for the subset of `package.json` the external loader reads.
|
|
62
|
+
*
|
|
63
|
+
* - `name` is the only required field; everything else is best-effort.
|
|
64
|
+
* - `vellum.requires` is forwarded to {@link PluginManifest.requires}
|
|
65
|
+
* verbatim (no merge with defaults) — empty objects propagate so the
|
|
66
|
+
* registry can reject under-specified plugins.
|
|
67
|
+
* - Unknown fields pass through (`passthrough`) so the loader does not
|
|
68
|
+
* destructively reshape the file when the rest of the npm ecosystem
|
|
69
|
+
* writes to it.
|
|
70
|
+
*/
|
|
71
|
+
const PluginPackageJsonSchema = z
|
|
72
|
+
.object({
|
|
73
|
+
name: z.string().min(1, "package.json `name` must be a non-empty string"),
|
|
74
|
+
version: z.string().optional(),
|
|
75
|
+
vellum: z
|
|
76
|
+
.object({
|
|
77
|
+
requires: z.record(z.string(), z.string()).optional(),
|
|
78
|
+
})
|
|
79
|
+
.passthrough()
|
|
80
|
+
.optional(),
|
|
81
|
+
})
|
|
82
|
+
.passthrough();
|
|
83
|
+
|
|
84
|
+
type PluginPackageJson = z.infer<typeof PluginPackageJsonSchema>;
|
|
85
|
+
|
|
86
|
+
export interface LoadExternalPluginOptions {
|
|
87
|
+
/**
|
|
88
|
+
* Maximum time to spend building the `Plugin` from disk before bailing.
|
|
89
|
+
* The build runs to completion in the background if it eventually
|
|
90
|
+
* resolves, but the loader has already moved on. Defaults to
|
|
91
|
+
* {@link DEFAULT_IMPORT_TIMEOUT_MS}.
|
|
92
|
+
*/
|
|
93
|
+
readonly importTimeoutMs?: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Strip the npm scope from a package name. `@vellumai/simple-memory` →
|
|
98
|
+
* `simple-memory`; an unscoped name passes through unchanged.
|
|
99
|
+
*/
|
|
100
|
+
function stripScope(name: string): string {
|
|
101
|
+
const match = /^@[^/]+\/(.+)$/.exec(name);
|
|
102
|
+
return match ? match[1]! : name;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Dynamic-import `absolutePath` and return its default export. Throws when
|
|
107
|
+
* the module has no default export — callers attribute the error.
|
|
108
|
+
*/
|
|
109
|
+
async function importDefault<T>(absolutePath: string): Promise<T> {
|
|
110
|
+
const url = pathToFileURL(absolutePath).href;
|
|
111
|
+
const mod = (await import(url)) as { default?: T };
|
|
112
|
+
if (mod.default === undefined) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`module ${absolutePath} has no default export — external plugins must default-export their interface surfaces`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return mod.default;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface SurfaceFile {
|
|
121
|
+
/** Basename without `.js`/`.ts` extension. */
|
|
122
|
+
readonly name: string;
|
|
123
|
+
/** Absolute path on disk. */
|
|
124
|
+
readonly path: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* List every `.js`/`.ts` file directly under `dir`, deduplicating `.js`
|
|
129
|
+
* over `.ts` when both are present for the same basename. Returns entries
|
|
130
|
+
* sorted by basename so plugin authors get a deterministic per-plugin
|
|
131
|
+
* registration sequence; cross-plugin order remains the registry's job.
|
|
132
|
+
*
|
|
133
|
+
* Used to walk both `hooks/` and `tools/` — neither surface needs
|
|
134
|
+
* subdirectory recursion today, so this stays flat on purpose.
|
|
135
|
+
*/
|
|
136
|
+
function listSurfaceDir(dir: string): SurfaceFile[] {
|
|
137
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory()) return [];
|
|
138
|
+
const entries = readdirSync(dir);
|
|
139
|
+
const byBase = new Map<string, string>();
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
// `.d.ts` declaration files are TypeScript type-only artifacts shipped
|
|
142
|
+
// alongside compiled `.js`. They have no default-exported runtime
|
|
143
|
+
// function and would crash `importDefault`, so the walker filters
|
|
144
|
+
// them out before the `.js`/`.ts` extension check.
|
|
145
|
+
if (entry.endsWith(".d.ts")) continue;
|
|
146
|
+
const base =
|
|
147
|
+
entry.endsWith(".js") || entry.endsWith(".ts")
|
|
148
|
+
? entry.slice(0, -3)
|
|
149
|
+
: null;
|
|
150
|
+
if (base === null) continue;
|
|
151
|
+
const existing = byBase.get(base);
|
|
152
|
+
if (
|
|
153
|
+
existing === undefined ||
|
|
154
|
+
(existing.endsWith(".ts") && entry.endsWith(".js"))
|
|
155
|
+
) {
|
|
156
|
+
byBase.set(base, entry);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return [...byBase.keys()]
|
|
160
|
+
.sort()
|
|
161
|
+
.map((name) => ({ name, path: join(dir, byBase.get(name)!) }));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Walk every file under `<pluginDir>/hooks/` and import each as a
|
|
166
|
+
* lifecycle hook keyed by filename basename. The runtime today invokes
|
|
167
|
+
* `init` at bootstrap and `shutdown` at teardown; other filenames are
|
|
168
|
+
* loaded into the map for forward compatibility with future lifecycle
|
|
169
|
+
* events but stay inert.
|
|
170
|
+
*/
|
|
171
|
+
async function loadHooks(
|
|
172
|
+
pluginDir: string,
|
|
173
|
+
pluginName: string,
|
|
174
|
+
): Promise<PluginHooks | undefined> {
|
|
175
|
+
const files = listSurfaceDir(join(pluginDir, "hooks"));
|
|
176
|
+
if (files.length === 0) return undefined;
|
|
177
|
+
const hooks: PluginHooks = {};
|
|
178
|
+
for (const { name, path } of files) {
|
|
179
|
+
const fn = await importDefault<PluginHookFn>(path);
|
|
180
|
+
if (typeof fn !== "function") {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`external plugin ${pluginName}: hooks/${name} default export must be a function (got ${typeof fn})`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
hooks[name] = fn;
|
|
186
|
+
}
|
|
187
|
+
return hooks;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Build a `Plugin` object from the directory layout. Internal — the
|
|
192
|
+
* public entry point ({@link loadExternalPlugin}) wraps this in the
|
|
193
|
+
* timeout/try-catch/register triple.
|
|
194
|
+
*/
|
|
195
|
+
async function buildPluginFromDir(pluginDir: string): Promise<Plugin> {
|
|
196
|
+
const pkgPath = join(pluginDir, "package.json");
|
|
197
|
+
let rawPkg: unknown;
|
|
198
|
+
try {
|
|
199
|
+
rawPkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
200
|
+
} catch (err) {
|
|
201
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
202
|
+
throw new Error(
|
|
203
|
+
`package.json at ${pluginDir} could not be read or parsed: ${reason}`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const parsed = PluginPackageJsonSchema.safeParse(rawPkg);
|
|
207
|
+
if (!parsed.success) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`package.json at ${pluginDir} failed schema validation: ${parsed.error.message}`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
const pkg: PluginPackageJson = parsed.data;
|
|
213
|
+
const name = stripScope(pkg.name);
|
|
214
|
+
const version = pkg.version && pkg.version.length > 0 ? pkg.version : "0.0.0";
|
|
215
|
+
|
|
216
|
+
// Default `requires` keeps the existing v1 negotiation working for
|
|
217
|
+
// plugins that have not yet opted into `vellum.requires`. Plugins that
|
|
218
|
+
// set `vellum.requires` get exactly what they declared — no merge.
|
|
219
|
+
const requires = pkg.vellum?.requires ?? { pluginRuntime: "v1" };
|
|
220
|
+
|
|
221
|
+
const manifest: PluginManifest = { name, version, requires };
|
|
222
|
+
const plugin: Plugin = { manifest };
|
|
223
|
+
|
|
224
|
+
const hooks = await loadHooks(pluginDir, name);
|
|
225
|
+
if (hooks !== undefined) plugin.hooks = hooks;
|
|
226
|
+
|
|
227
|
+
const tools: PluginToolRegistration[] = [];
|
|
228
|
+
for (const { path: toolPath } of listSurfaceDir(join(pluginDir, "tools"))) {
|
|
229
|
+
const tool = await importDefault<PluginToolRegistration>(toolPath);
|
|
230
|
+
if (
|
|
231
|
+
tool === null ||
|
|
232
|
+
typeof tool !== "object" ||
|
|
233
|
+
typeof (tool as { name?: unknown }).name !== "string"
|
|
234
|
+
) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`external plugin ${name}: ${toolPath} default export must be a Tool object with a string "name"`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
tools.push(tool);
|
|
240
|
+
}
|
|
241
|
+
if (tools.length > 0) plugin.tools = tools;
|
|
242
|
+
|
|
243
|
+
return plugin;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Load the external plugin at `pluginDir` and register it.
|
|
248
|
+
*/
|
|
249
|
+
export async function loadExternalPlugin(
|
|
250
|
+
pluginDir: string,
|
|
251
|
+
opts: LoadExternalPluginOptions = {},
|
|
252
|
+
): Promise<void> {
|
|
253
|
+
const timeoutMs = opts.importTimeoutMs ?? DEFAULT_IMPORT_TIMEOUT_MS;
|
|
254
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
255
|
+
try {
|
|
256
|
+
const timeoutSentinel = Symbol("external-plugin-load-timeout");
|
|
257
|
+
const buildPromise = buildPluginFromDir(pluginDir);
|
|
258
|
+
const timeoutPromise = new Promise<typeof timeoutSentinel>((resolve) => {
|
|
259
|
+
timeoutHandle = setTimeout(() => resolve(timeoutSentinel), timeoutMs);
|
|
260
|
+
});
|
|
261
|
+
const result = await Promise.race([buildPromise, timeoutPromise]);
|
|
262
|
+
if (result === timeoutSentinel) {
|
|
263
|
+
// Abandoned build — surface imports may still be running. Attach a
|
|
264
|
+
// terminal `.catch` so a late rejection does not surface as an
|
|
265
|
+
// unhandled-rejection crash. The closed-registration latch in
|
|
266
|
+
// `registry.ts` rejects any late `registerPlugin()` call from a
|
|
267
|
+
// surface module that finishes evaluating after this loader has
|
|
268
|
+
// moved on.
|
|
269
|
+
buildPromise.catch(() => {
|
|
270
|
+
/* swallow — see comment above */
|
|
271
|
+
});
|
|
272
|
+
log.warn(
|
|
273
|
+
{ pluginDir, timeoutMs },
|
|
274
|
+
`Timed out loading external plugin ${pluginDir} after ${timeoutMs}ms — skipping`,
|
|
275
|
+
);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
registerPlugin(result);
|
|
279
|
+
log.info(
|
|
280
|
+
{ pluginDir, name: result.manifest.name },
|
|
281
|
+
"loaded external plugin",
|
|
282
|
+
);
|
|
283
|
+
} catch (err) {
|
|
284
|
+
// Per-plugin isolation: one bad external plugin must not crash the
|
|
285
|
+
// daemon. Surface the failure with attribution and move on.
|
|
286
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
287
|
+
log.error(
|
|
288
|
+
{ err, pluginDir },
|
|
289
|
+
`Failed to load external plugin ${pluginDir}: ${message}`,
|
|
290
|
+
);
|
|
291
|
+
} finally {
|
|
292
|
+
if (timeoutHandle !== undefined) clearTimeout(timeoutHandle);
|
|
293
|
+
}
|
|
294
|
+
}
|
package/src/plugins/types.ts
CHANGED
|
@@ -93,30 +93,14 @@ export interface PluginManifest {
|
|
|
93
93
|
config?: unknown;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
// ─── Init context
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/** Parsed config for this plugin (may be `unknown` until the manifest validates). */
|
|
105
|
-
config: unknown;
|
|
106
|
-
/** Resolved credential values keyed by the entries of `manifest.requiresCredential`. */
|
|
107
|
-
credentials: Record<string, string>;
|
|
108
|
-
/**
|
|
109
|
-
* Pino-compatible child logger bound to `{ plugin: <name> }`. Untyped here
|
|
110
|
-
* to avoid pulling pino into the types module.
|
|
111
|
-
*/
|
|
112
|
-
logger: unknown;
|
|
113
|
-
/** Absolute path to `<workspaceDir>/plugins-data/<plugin>/` (created by bootstrap). */
|
|
114
|
-
pluginStorageDir: string;
|
|
115
|
-
/** Assistant semver for compatibility checks inside the plugin. */
|
|
116
|
-
assistantVersion: string;
|
|
117
|
-
/** Capability → version-list map (`ASSISTANT_API_VERSIONS`) for defensive runtime checks. */
|
|
118
|
-
apiVersions: Record<string, string[]>;
|
|
119
|
-
}
|
|
96
|
+
// ─── Init / Shutdown context ─────────────────────────────────────────────────
|
|
97
|
+
// Public types — defined in `assistant/src/plugin-api/types.ts` and re-exported
|
|
98
|
+
// here so existing internal call sites keep working. Plugin authors will
|
|
99
|
+
// import these from `@vellumai/plugin-api` once that package is published.
|
|
100
|
+
export type {
|
|
101
|
+
PluginInitContext,
|
|
102
|
+
PluginShutdownContext,
|
|
103
|
+
} from "../plugin-api/types.js";
|
|
120
104
|
|
|
121
105
|
// ─── Middleware ──────────────────────────────────────────────────────────────
|
|
122
106
|
|
|
@@ -1077,19 +1061,51 @@ export interface PluginSkillRegistration {
|
|
|
1077
1061
|
|
|
1078
1062
|
// ─── Plugin ──────────────────────────────────────────────────────────────────
|
|
1079
1063
|
|
|
1064
|
+
/**
|
|
1065
|
+
* A plugin lifecycle hook. Receives a per-lifecycle context shape and
|
|
1066
|
+
* may return either a transformed context or `void`. Today's runtime
|
|
1067
|
+
* consumes only the resolved-or-rejected nature of the promise; the
|
|
1068
|
+
* `TCtx` return is reserved for future hooks that fan a transformed
|
|
1069
|
+
* context out to downstream plugins.
|
|
1070
|
+
*
|
|
1071
|
+
* Each known hook key has a documented context shape:
|
|
1072
|
+
* - `init` — {@link PluginInitContext}
|
|
1073
|
+
* - `shutdown` — {@link PluginShutdownContext}
|
|
1074
|
+
*
|
|
1075
|
+
* Unknown keys are populated by the loader for forward compatibility
|
|
1076
|
+
* but are not invoked by today's runtime.
|
|
1077
|
+
*/
|
|
1078
|
+
export type PluginHookFn<TCtx = unknown> = (
|
|
1079
|
+
ctx: TCtx,
|
|
1080
|
+
) => Promise<TCtx | void>;
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Map of lifecycle hooks contributed by a plugin. Keys match file
|
|
1084
|
+
* basenames under `<plugin>/hooks/` — the external loader populates one
|
|
1085
|
+
* entry per `hooks/<name>.{ts,js}` it finds. The runtime invokes
|
|
1086
|
+
* known keys (`init`, `shutdown`) at the matching lifecycle event;
|
|
1087
|
+
* unknown keys are forward-compat scaffolding.
|
|
1088
|
+
*
|
|
1089
|
+
* See `assistant/src/daemon/external-plugins-bootstrap.ts` for the
|
|
1090
|
+
* full lifecycle, and {@link PluginHookFn} for the per-entry signature.
|
|
1091
|
+
*/
|
|
1092
|
+
// The map stores hooks for arbitrary keys with arbitrary context shapes.
|
|
1093
|
+
// `any` (rather than `unknown`) is required so concrete plugin signatures
|
|
1094
|
+
// like `(ctx: PluginInitContext) => Promise<void>` and `() => Promise<void>`
|
|
1095
|
+
// both assign in/out of slot entries under strict-function-types contravariance.
|
|
1096
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1097
|
+
export type PluginHooks = Record<string, PluginHookFn<any>>;
|
|
1098
|
+
|
|
1080
1099
|
/**
|
|
1081
1100
|
* A registered plugin. Every field besides `manifest` is optional — a plugin
|
|
1082
1101
|
* may contribute any combination of middleware, injectors, and model-visible
|
|
1083
|
-
* capabilities. Lifecycle hooks
|
|
1084
|
-
* during daemon startup/shutdown.
|
|
1102
|
+
* capabilities. Lifecycle hooks live under `hooks`.
|
|
1085
1103
|
*/
|
|
1086
1104
|
export interface Plugin {
|
|
1087
1105
|
/** Static manifest validated by the registry. */
|
|
1088
1106
|
manifest: PluginManifest;
|
|
1089
|
-
/**
|
|
1090
|
-
|
|
1091
|
-
/** Optional shutdown hook. Runs during daemon shutdown in reverse-registration order. */
|
|
1092
|
-
onShutdown?(): Promise<void>;
|
|
1107
|
+
/** Lifecycle hooks (init, shutdown). See {@link PluginHooks}. */
|
|
1108
|
+
hooks?: PluginHooks;
|
|
1093
1109
|
/** Tool registrations visible to the model. */
|
|
1094
1110
|
tools?: PluginToolRegistration[];
|
|
1095
1111
|
/** HTTP route registrations served by the assistant. */
|