@vellumai/assistant 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +13 -19
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +17 -0
- package/docker-init-apt-root.sh +167 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +642 -5
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +147 -0
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +31 -65
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +59 -1
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +102 -13
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +3 -2
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +151 -55
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +507 -10
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +15 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +99 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +58 -13
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +36 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-resolver.test.ts +255 -2
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +41 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +242 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +7 -2
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +158 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +33 -31
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +1 -1
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +670 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/agent/loop.ts +167 -18
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +122 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +960 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +388 -346
- package/src/cli/commands/plugins.ts +252 -0
- package/src/cli/commands/schedules.ts +683 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +303 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +52 -2
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +140 -22
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/call-site-defaults.ts +105 -0
- package/src/config/feature-flag-registry.json +41 -9
- package/src/config/llm-resolver.ts +52 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +9 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
- package/src/config/schemas/channels.ts +17 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +23 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +4 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1107 -0
- package/src/context/token-estimator.ts +34 -36
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +33 -18
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
- package/src/daemon/conversation-agent-loop.ts +198 -11
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +25 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -8
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +289 -0
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/conversations.ts +1 -0
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +153 -27
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/lifecycle.ts +89 -91
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +85 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +11 -54
- package/src/daemon/pkb-reminder-builder.ts +5 -20
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +24 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +33 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +135 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +73 -189
- package/src/home/__tests__/feed-types.test.ts +80 -0
- package/src/home/feed-types.ts +36 -2
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/ipc/cli-client.ts +147 -45
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +483 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +197 -11
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +12 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +150 -12
- package/src/memory/graph/conversation-graph-memory.ts +49 -21
- package/src/memory/graph/tools.ts +9 -40
- package/src/memory/indexer.ts +34 -29
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +24 -12
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-enqueue.ts +1 -20
- package/src/memory/memory-retrospective-job.ts +33 -6
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/index.ts +9 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +3 -3
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection.test.ts +288 -11
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection.ts +81 -26
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +63 -8
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +11 -2
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +113 -45
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +21 -1
- package/src/notifications/home-feed-side-effect.ts +138 -5
- package/src/notifications/signal.ts +3 -5
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +19 -6
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +74 -22
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +187 -42
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +40 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +10 -43
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +95 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -174
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +164 -0
- package/src/providers/__tests__/inference.test.ts +24 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +68 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +32 -6
- package/src/providers/inference/auth.ts +12 -0
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/connections.ts +159 -34
- package/src/providers/inference/resolve-auth.ts +14 -4
- package/src/providers/model-catalog.ts +249 -12
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +169 -8
- package/src/providers/openrouter/client.ts +49 -4
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -2
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +38 -0
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +52 -15
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +103 -15
- package/src/runtime/auth/route-policy.ts +21 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +19 -47
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +172 -23
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +126 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +99 -35
- package/src/runtime/routes/conversation-routes.ts +97 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +199 -22
- package/src/runtime/routes/integrations/a2a.ts +235 -0
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +98 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +17 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +107 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
|
@@ -67,6 +67,43 @@ export interface FetchManagedCatalogResult {
|
|
|
67
67
|
error?: string;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Managed connection cache — provides a synchronous view of platform-managed
|
|
72
|
+
// connections for use in the system prompt (which is built synchronously).
|
|
73
|
+
// Refresh is triggered at daemon startup and periodically via setInterval.
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
export interface CachedManagedConnection {
|
|
77
|
+
provider: string;
|
|
78
|
+
accountInfo: string | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let cachedConnections: CachedManagedConnection[] = [];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Return the last successfully fetched managed connections.
|
|
85
|
+
* Returns an empty array before the first successful refresh.
|
|
86
|
+
*/
|
|
87
|
+
export function getCachedManagedConnections(): CachedManagedConnection[] {
|
|
88
|
+
return cachedConnections;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Fetch managed connections from the platform and update the in-memory cache.
|
|
93
|
+
* Best-effort: errors are logged and the cache retains its previous value.
|
|
94
|
+
*/
|
|
95
|
+
export async function refreshManagedConnectionCache(): Promise<void> {
|
|
96
|
+
const result = await fetchManagedCatalog();
|
|
97
|
+
if (result.ok) {
|
|
98
|
+
cachedConnections = result.descriptors
|
|
99
|
+
.filter((d) => d.status === "active" || d.status === "ACTIVE")
|
|
100
|
+
.map((d) => ({
|
|
101
|
+
provider: d.provider,
|
|
102
|
+
accountInfo: d.accountInfo,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
70
107
|
/**
|
|
71
108
|
* Fetch the managed credential catalog from the platform.
|
|
72
109
|
*
|
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
|
|
14
14
|
import { isTokenExpired } from "@vellumai/credential-storage";
|
|
15
15
|
|
|
16
|
+
import type { Services } from "../config/schemas/services.js";
|
|
16
17
|
import { getConnectionAccessTokenResult } from "../oauth/credential-token-resolver.js";
|
|
17
18
|
import {
|
|
18
19
|
getProvider,
|
|
19
20
|
listActiveConnectionsByProvider,
|
|
20
21
|
listProviders,
|
|
22
|
+
type OAuthConnectionRow,
|
|
23
|
+
type OAuthProviderRow,
|
|
21
24
|
} from "../oauth/oauth-store.js";
|
|
22
25
|
import { getLogger } from "../util/logger.js";
|
|
23
26
|
|
|
@@ -271,6 +274,207 @@ async function checkConnection(
|
|
|
271
274
|
};
|
|
272
275
|
}
|
|
273
276
|
|
|
277
|
+
// ── Managed provider checks ──────────────────────────────────────────
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Check whether a provider is configured in managed mode.
|
|
281
|
+
* Uses dynamic imports to avoid circular dependencies (same pattern as
|
|
282
|
+
* `integration-status.ts`).
|
|
283
|
+
*/
|
|
284
|
+
async function isManagedProvider(
|
|
285
|
+
providerRow: OAuthProviderRow,
|
|
286
|
+
): Promise<boolean> {
|
|
287
|
+
const managedKey = providerRow.managedServiceConfigKey;
|
|
288
|
+
if (!managedKey) return false;
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
const { ServicesSchema, getServiceMode } =
|
|
292
|
+
await import("../config/schemas/services.js");
|
|
293
|
+
if (!(managedKey in ServicesSchema.shape)) return false;
|
|
294
|
+
|
|
295
|
+
const { getConfig } = await import("../config/loader.js");
|
|
296
|
+
const services: Services = getConfig().services;
|
|
297
|
+
return getServiceMode(services, managedKey as keyof Services) === "managed";
|
|
298
|
+
} catch {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Fetch active managed connections from the platform and ping each one.
|
|
305
|
+
* Returns health results for managed connections, or an empty array if
|
|
306
|
+
* the platform is unreachable or the provider is not managed.
|
|
307
|
+
*/
|
|
308
|
+
async function checkManagedProvider(
|
|
309
|
+
providerRow: OAuthProviderRow,
|
|
310
|
+
): Promise<CredentialHealthResult[]> {
|
|
311
|
+
const results: CredentialHealthResult[] = [];
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
const { VellumPlatformClient } = await import("../platform/client.js");
|
|
315
|
+
const client = await VellumPlatformClient.create();
|
|
316
|
+
if (!client?.platformAssistantId) return results;
|
|
317
|
+
|
|
318
|
+
const params = new URLSearchParams();
|
|
319
|
+
params.set("provider", providerRow.provider);
|
|
320
|
+
params.set("status", "ACTIVE");
|
|
321
|
+
|
|
322
|
+
const path = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/oauth/connections/?${params.toString()}`;
|
|
323
|
+
const response = await client.fetch(path);
|
|
324
|
+
|
|
325
|
+
if (!response.ok) {
|
|
326
|
+
log.warn(
|
|
327
|
+
{ status: response.status, provider: providerRow.provider },
|
|
328
|
+
"Failed to list managed connections for health check",
|
|
329
|
+
);
|
|
330
|
+
return results;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const body = (await response.json()) as unknown;
|
|
334
|
+
const connections = (
|
|
335
|
+
Array.isArray(body)
|
|
336
|
+
? body
|
|
337
|
+
: ((body as Record<string, unknown>).results ?? [])
|
|
338
|
+
) as Array<{ id: string; account_label?: string }>;
|
|
339
|
+
|
|
340
|
+
if (connections.length === 0) {
|
|
341
|
+
// No active managed connections — report as missing so the
|
|
342
|
+
// heartbeat can notify the user.
|
|
343
|
+
results.push({
|
|
344
|
+
connectionId: `managed:${providerRow.provider}`,
|
|
345
|
+
provider: providerRow.provider,
|
|
346
|
+
accountInfo: null,
|
|
347
|
+
status: "missing_token",
|
|
348
|
+
details: `No active managed connection for ${providerRow.provider}. Reconnect on the Vellum platform.`,
|
|
349
|
+
missingScopes: [],
|
|
350
|
+
canAutoRecover: false,
|
|
351
|
+
});
|
|
352
|
+
return results;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Ping each managed connection via the platform proxy
|
|
356
|
+
for (const conn of connections) {
|
|
357
|
+
const base: Omit<
|
|
358
|
+
CredentialHealthResult,
|
|
359
|
+
"status" | "details" | "canAutoRecover"
|
|
360
|
+
> = {
|
|
361
|
+
connectionId: conn.id,
|
|
362
|
+
provider: providerRow.provider,
|
|
363
|
+
accountInfo: conn.account_label ?? null,
|
|
364
|
+
missingScopes: [],
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
if (!providerRow.pingUrl) {
|
|
368
|
+
// No ping URL configured — assume healthy if connection exists
|
|
369
|
+
results.push({
|
|
370
|
+
...base,
|
|
371
|
+
status: "healthy",
|
|
372
|
+
details: `${providerRow.provider} managed connection is active (no ping URL configured).`,
|
|
373
|
+
canAutoRecover: true,
|
|
374
|
+
});
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Ping via platform proxy
|
|
379
|
+
try {
|
|
380
|
+
const { PlatformOAuthConnection } =
|
|
381
|
+
await import("../oauth/platform-connection.js");
|
|
382
|
+
const platformConn = new PlatformOAuthConnection({
|
|
383
|
+
id: conn.id,
|
|
384
|
+
provider: providerRow.provider,
|
|
385
|
+
externalId: providerRow.provider,
|
|
386
|
+
accountInfo: conn.account_label ?? null,
|
|
387
|
+
client,
|
|
388
|
+
connectionId: conn.id,
|
|
389
|
+
baseUrl: undefined,
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Decompose the absolute pingUrl into base URL + relative path.
|
|
393
|
+
// OAuthConnectionRequest.path is documented as relative, but
|
|
394
|
+
// provider definitions store full absolute URLs.
|
|
395
|
+
const parsedPingUrl = new URL(providerRow.pingUrl);
|
|
396
|
+
const pingBaseUrl = `${parsedPingUrl.protocol}//${parsedPingUrl.host}`;
|
|
397
|
+
const pingPath = parsedPingUrl.pathname + parsedPingUrl.search;
|
|
398
|
+
|
|
399
|
+
const parsedHeaders = safeJsonParse<Record<string, string>>(
|
|
400
|
+
providerRow.pingHeaders,
|
|
401
|
+
{},
|
|
402
|
+
);
|
|
403
|
+
const parsedBody = safeJsonParse<unknown>(providerRow.pingBody, null);
|
|
404
|
+
|
|
405
|
+
const pingResp = await platformConn.request({
|
|
406
|
+
method: providerRow.pingMethod ?? "GET",
|
|
407
|
+
path: pingPath,
|
|
408
|
+
baseUrl: pingBaseUrl,
|
|
409
|
+
...(Object.keys(parsedHeaders).length > 0
|
|
410
|
+
? { headers: parsedHeaders }
|
|
411
|
+
: {}),
|
|
412
|
+
...(parsedBody != null ? { body: parsedBody } : {}),
|
|
413
|
+
signal: AbortSignal.timeout(PING_TIMEOUT_MS),
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
if (pingResp.status >= 200 && pingResp.status < 300) {
|
|
417
|
+
results.push({
|
|
418
|
+
...base,
|
|
419
|
+
status: "healthy",
|
|
420
|
+
details: `${providerRow.provider} managed credential is healthy.`,
|
|
421
|
+
canAutoRecover: true,
|
|
422
|
+
});
|
|
423
|
+
} else if (pingResp.status === 401 || pingResp.status === 403) {
|
|
424
|
+
results.push({
|
|
425
|
+
...base,
|
|
426
|
+
status: "revoked",
|
|
427
|
+
details: `${providerRow.provider} managed token was rejected (${pingResp.status}). Reconnect on the Vellum platform.`,
|
|
428
|
+
canAutoRecover: false,
|
|
429
|
+
});
|
|
430
|
+
} else {
|
|
431
|
+
results.push({
|
|
432
|
+
...base,
|
|
433
|
+
status: "ping_failed",
|
|
434
|
+
details: `${providerRow.provider} managed liveness check returned ${pingResp.status}.`,
|
|
435
|
+
canAutoRecover: false,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
} catch (err) {
|
|
439
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
440
|
+
// CredentialRequiredError means the platform can't materialize
|
|
441
|
+
// the token — treat as revoked.
|
|
442
|
+
if (
|
|
443
|
+
err &&
|
|
444
|
+
typeof err === "object" &&
|
|
445
|
+
"name" in err &&
|
|
446
|
+
(err as { name: string }).name === "CredentialRequiredError"
|
|
447
|
+
) {
|
|
448
|
+
results.push({
|
|
449
|
+
...base,
|
|
450
|
+
status: "revoked",
|
|
451
|
+
details: `${providerRow.provider} managed connection is no longer valid. Reconnect on the Vellum platform.`,
|
|
452
|
+
canAutoRecover: false,
|
|
453
|
+
});
|
|
454
|
+
} else {
|
|
455
|
+
log.debug(
|
|
456
|
+
{ provider: providerRow.provider, connectionId: conn.id, err: msg },
|
|
457
|
+
"Managed credential ping failed",
|
|
458
|
+
);
|
|
459
|
+
results.push({
|
|
460
|
+
...base,
|
|
461
|
+
status: "ping_failed",
|
|
462
|
+
details: `${providerRow.provider} managed liveness check failed: ${msg}`,
|
|
463
|
+
canAutoRecover: false,
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
} catch (err) {
|
|
469
|
+
log.warn(
|
|
470
|
+
{ err, provider: providerRow.provider },
|
|
471
|
+
"Failed to check managed provider health",
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return results;
|
|
476
|
+
}
|
|
477
|
+
|
|
274
478
|
// ── Public API ────────────────────────────────────────────────────────
|
|
275
479
|
|
|
276
480
|
/**
|
|
@@ -279,6 +483,9 @@ async function checkConnection(
|
|
|
279
483
|
* Iterates every registered provider, looks up active connections, and
|
|
280
484
|
* validates each one. Returns a structured report with overall results
|
|
281
485
|
* and a filtered list of unhealthy credentials.
|
|
486
|
+
*
|
|
487
|
+
* Checks both BYO (local SQLite) and managed (platform-hosted)
|
|
488
|
+
* connections.
|
|
282
489
|
*/
|
|
283
490
|
export async function checkAllCredentials(): Promise<CredentialHealthReport> {
|
|
284
491
|
const checkedAt = Date.now();
|
|
@@ -292,6 +499,10 @@ export async function checkAllCredentials(): Promise<CredentialHealthReport> {
|
|
|
292
499
|
return { checkedAt, results, unhealthy: [] };
|
|
293
500
|
}
|
|
294
501
|
|
|
502
|
+
// Track which providers have BYO connections so we skip the managed
|
|
503
|
+
// check for them (they're already covered by the BYO path).
|
|
504
|
+
const byoProviders = new Set<string>();
|
|
505
|
+
|
|
295
506
|
for (const providerRow of providers) {
|
|
296
507
|
let connections;
|
|
297
508
|
try {
|
|
@@ -304,6 +515,10 @@ export async function checkAllCredentials(): Promise<CredentialHealthReport> {
|
|
|
304
515
|
continue;
|
|
305
516
|
}
|
|
306
517
|
|
|
518
|
+
if (connections.length > 0) {
|
|
519
|
+
byoProviders.add(providerRow.provider);
|
|
520
|
+
}
|
|
521
|
+
|
|
307
522
|
for (const conn of connections) {
|
|
308
523
|
try {
|
|
309
524
|
const result = await checkConnection({
|
|
@@ -329,6 +544,36 @@ export async function checkAllCredentials(): Promise<CredentialHealthReport> {
|
|
|
329
544
|
}
|
|
330
545
|
}
|
|
331
546
|
|
|
547
|
+
// Check managed connections. If a provider is currently in managed mode,
|
|
548
|
+
// evaluate it via the managed path even if stale BYO rows exist — the
|
|
549
|
+
// user may have switched from BYO to managed.
|
|
550
|
+
for (const providerRow of providers) {
|
|
551
|
+
if (!(await isManagedProvider(providerRow))) continue;
|
|
552
|
+
|
|
553
|
+
// If the provider is in managed mode and also has BYO connections,
|
|
554
|
+
// remove the stale BYO results — managed mode takes priority.
|
|
555
|
+
if (byoProviders.has(providerRow.provider)) {
|
|
556
|
+
const beforeLen = results.length;
|
|
557
|
+
const filtered = results.filter(
|
|
558
|
+
(r) => r.provider !== providerRow.provider,
|
|
559
|
+
);
|
|
560
|
+
if (filtered.length !== beforeLen) {
|
|
561
|
+
results.length = 0;
|
|
562
|
+
results.push(...filtered);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
const managedResults = await checkManagedProvider(providerRow);
|
|
568
|
+
results.push(...managedResults);
|
|
569
|
+
} catch (err) {
|
|
570
|
+
log.warn(
|
|
571
|
+
{ err, provider: providerRow.provider },
|
|
572
|
+
"Failed to check managed provider health",
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
332
577
|
const unhealthy = results.filter((r) => r.status !== "healthy");
|
|
333
578
|
if (unhealthy.length > 0) {
|
|
334
579
|
log.info(
|
|
@@ -351,34 +596,50 @@ export async function checkAllCredentials(): Promise<CredentialHealthReport> {
|
|
|
351
596
|
* result for the most recent active connection, or null if no connection
|
|
352
597
|
* exists.
|
|
353
598
|
*
|
|
599
|
+
* Checks BYO connections first; if none exist, falls back to checking
|
|
600
|
+
* managed connections on the platform.
|
|
601
|
+
*
|
|
354
602
|
* Used by the watcher engine for pre-poll gating.
|
|
355
603
|
*/
|
|
356
604
|
export async function checkCredentialForProvider(
|
|
357
605
|
provider: string,
|
|
358
606
|
): Promise<CredentialHealthResult | null> {
|
|
359
|
-
|
|
607
|
+
const providerRow = getProvider(provider);
|
|
608
|
+
if (!providerRow) return null;
|
|
609
|
+
|
|
610
|
+
// Check managed mode first — if the provider is currently configured for
|
|
611
|
+
// managed mode, evaluate via the platform regardless of stale BYO rows.
|
|
612
|
+
if (await isManagedProvider(providerRow)) {
|
|
613
|
+
const managedResults = await checkManagedProvider(providerRow);
|
|
614
|
+
if (managedResults.length > 0) return managedResults[0]!;
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Fall back to BYO (local) connection check.
|
|
619
|
+
let connections: OAuthConnectionRow[];
|
|
360
620
|
try {
|
|
361
621
|
connections = listActiveConnectionsByProvider(provider);
|
|
362
622
|
} catch {
|
|
363
|
-
|
|
623
|
+
connections = [];
|
|
364
624
|
}
|
|
365
|
-
if (connections.length === 0) return null;
|
|
366
625
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
626
|
+
if (connections.length > 0) {
|
|
627
|
+
const conn = connections[0]!;
|
|
628
|
+
|
|
629
|
+
return checkConnection({
|
|
630
|
+
connectionId: conn.id,
|
|
631
|
+
provider: conn.provider,
|
|
632
|
+
accountInfo: conn.accountInfo,
|
|
633
|
+
expiresAt: conn.expiresAt,
|
|
634
|
+
hasRefreshToken: !!conn.hasRefreshToken,
|
|
635
|
+
grantedScopesRaw: conn.grantedScopes,
|
|
636
|
+
defaultScopesRaw: providerRow.defaultScopes,
|
|
637
|
+
pingUrl: providerRow.pingUrl,
|
|
638
|
+
pingMethod: providerRow.pingMethod,
|
|
639
|
+
pingHeaders: providerRow.pingHeaders,
|
|
640
|
+
pingBody: providerRow.pingBody,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
370
643
|
|
|
371
|
-
return
|
|
372
|
-
connectionId: conn.id,
|
|
373
|
-
provider: conn.provider,
|
|
374
|
-
accountInfo: conn.accountInfo,
|
|
375
|
-
expiresAt: conn.expiresAt,
|
|
376
|
-
hasRefreshToken: !!conn.hasRefreshToken,
|
|
377
|
-
grantedScopesRaw: conn.grantedScopes,
|
|
378
|
-
defaultScopesRaw: providerRow.defaultScopes,
|
|
379
|
-
pingUrl: providerRow.pingUrl,
|
|
380
|
-
pingMethod: providerRow.pingMethod,
|
|
381
|
-
pingHeaders: providerRow.pingHeaders,
|
|
382
|
-
pingBody: providerRow.pingBody,
|
|
383
|
-
});
|
|
644
|
+
return null;
|
|
384
645
|
}
|
|
@@ -62,8 +62,11 @@ const autoAnalysisConversations = new Set<string>();
|
|
|
62
62
|
// flip this to true.
|
|
63
63
|
let v2Enabled = false;
|
|
64
64
|
|
|
65
|
+
const realLoader = await import("../../config/loader.js");
|
|
65
66
|
mock.module("../../config/loader.js", () => ({
|
|
67
|
+
...realLoader,
|
|
66
68
|
getConfig: () => ({ memory: { v2: { enabled: v2Enabled } } }),
|
|
69
|
+
loadConfig: () => ({ memory: { v2: { enabled: v2Enabled } } }),
|
|
67
70
|
}));
|
|
68
71
|
|
|
69
72
|
mock.module("../../memory/auto-analysis-guard.js", () => ({
|
|
@@ -81,7 +84,10 @@ mock.module("../../memory/jobs-store.js", () => ({
|
|
|
81
84
|
},
|
|
82
85
|
}));
|
|
83
86
|
|
|
87
|
+
const realAutoAnalysisEnqueue =
|
|
88
|
+
await import("../../memory/auto-analysis-enqueue.js");
|
|
84
89
|
mock.module("../../memory/auto-analysis-enqueue.js", () => ({
|
|
90
|
+
...realAutoAnalysisEnqueue,
|
|
85
91
|
enqueueAutoAnalysisIfEnabled: (args: {
|
|
86
92
|
conversationId: string;
|
|
87
93
|
trigger: "batch" | "idle" | "lifecycle";
|
|
@@ -91,7 +97,6 @@ mock.module("../../memory/auto-analysis-enqueue.js", () => ({
|
|
|
91
97
|
},
|
|
92
98
|
}));
|
|
93
99
|
|
|
94
|
-
let memoryRetroEnabled = false;
|
|
95
100
|
const memoryRetroCalls: Array<{
|
|
96
101
|
conversationId: string;
|
|
97
102
|
trigger: string;
|
|
@@ -102,7 +107,6 @@ mock.module("../../memory/memory-retrospective-enqueue.js", () => ({
|
|
|
102
107
|
conversationId: string;
|
|
103
108
|
trigger: string;
|
|
104
109
|
}) => {
|
|
105
|
-
if (!memoryRetroEnabled) return;
|
|
106
110
|
memoryRetroCalls.push(args);
|
|
107
111
|
},
|
|
108
112
|
// Also export sibling functions other modules import from this file, so
|
|
@@ -114,15 +118,23 @@ mock.module("../../memory/memory-retrospective-enqueue.js", () => ({
|
|
|
114
118
|
|
|
115
119
|
// Stub all side-effecting cleanup helpers that disposeConversation chains
|
|
116
120
|
// into after the enqueue block. We assert on enqueue behavior only.
|
|
121
|
+
const realBrowserScreencast =
|
|
122
|
+
await import("../../tools/browser/browser-screencast.js");
|
|
117
123
|
mock.module("../../tools/browser/browser-screencast.js", () => ({
|
|
124
|
+
...realBrowserScreencast,
|
|
118
125
|
unregisterConversationSender: () => {},
|
|
119
126
|
}));
|
|
120
127
|
|
|
128
|
+
const realConversationNotifiers = await import("../conversation-notifiers.js");
|
|
121
129
|
mock.module("../conversation-notifiers.js", () => ({
|
|
130
|
+
...realConversationNotifiers,
|
|
122
131
|
unregisterCallNotifiers: () => {},
|
|
123
132
|
}));
|
|
124
133
|
|
|
134
|
+
const realConversationSkillTools =
|
|
135
|
+
await import("../conversation-skill-tools.js");
|
|
125
136
|
mock.module("../conversation-skill-tools.js", () => ({
|
|
137
|
+
...realConversationSkillTools,
|
|
126
138
|
resetSkillToolProjection: () => {},
|
|
127
139
|
}));
|
|
128
140
|
|
|
@@ -191,7 +203,6 @@ describe("disposeConversation — auto-analysis enqueue", () => {
|
|
|
191
203
|
autoAnalyzeCalls.length = 0;
|
|
192
204
|
memoryRetroCalls.length = 0;
|
|
193
205
|
autoAnalyzeEnabled = true;
|
|
194
|
-
memoryRetroEnabled = false;
|
|
195
206
|
autoAnalysisConversations.clear();
|
|
196
207
|
v2Enabled = false;
|
|
197
208
|
});
|
|
@@ -376,13 +387,11 @@ describe("disposeConversation — memory-retrospective lifecycle safety net", ()
|
|
|
376
387
|
autoAnalyzeCalls.length = 0;
|
|
377
388
|
memoryRetroCalls.length = 0;
|
|
378
389
|
autoAnalyzeEnabled = false;
|
|
379
|
-
memoryRetroEnabled = false;
|
|
380
390
|
autoAnalysisConversations.clear();
|
|
381
391
|
v2Enabled = false;
|
|
382
392
|
});
|
|
383
393
|
|
|
384
|
-
test("guardian conversation
|
|
385
|
-
memoryRetroEnabled = true;
|
|
394
|
+
test("guardian conversation — enqueues memory-retrospective with trigger 'lifecycle'", () => {
|
|
386
395
|
const ctx = makeDisposeContext({
|
|
387
396
|
conversationId: "conv-retro",
|
|
388
397
|
trustClass: "guardian",
|
|
@@ -397,31 +406,37 @@ describe("disposeConversation — memory-retrospective lifecycle safety net", ()
|
|
|
397
406
|
});
|
|
398
407
|
});
|
|
399
408
|
|
|
400
|
-
test("
|
|
401
|
-
memoryRetroEnabled = false;
|
|
409
|
+
test("untrusted actor — no memory-retrospective enqueue", () => {
|
|
402
410
|
const ctx = makeDisposeContext({
|
|
403
|
-
conversationId: "conv-retro-
|
|
404
|
-
trustClass: "
|
|
411
|
+
conversationId: "conv-retro-untrusted",
|
|
412
|
+
trustClass: "unknown",
|
|
405
413
|
});
|
|
406
414
|
|
|
407
415
|
disposeConversation(ctx);
|
|
408
416
|
|
|
417
|
+
// The outer trust-class guard in disposeConversation gates ALL three
|
|
418
|
+
// enqueues (graph_extract, auto-analyze, memory-retrospective). When
|
|
419
|
+
// the actor is untrusted, none of them fire.
|
|
409
420
|
expect(memoryRetroCalls).toHaveLength(0);
|
|
421
|
+
expect(autoAnalyzeCalls).toHaveLength(0);
|
|
410
422
|
});
|
|
411
423
|
|
|
412
|
-
|
|
413
|
-
|
|
424
|
+
// Regression test: the retrospective lifecycle enqueue was previously
|
|
425
|
+
// outside the `!isAutoAnalysis` guard, so it fired even for auto-analysis
|
|
426
|
+
// conversations. Mirrors the indexer-time gate in `indexer.ts` and
|
|
427
|
+
// matches the existing graph_extract recursion-guard semantics.
|
|
428
|
+
test("auto-analysis conversation — does NOT enqueue memory-retrospective", () => {
|
|
429
|
+
autoAnalysisConversations.add("conv-auto-retro");
|
|
414
430
|
const ctx = makeDisposeContext({
|
|
415
|
-
conversationId: "conv-retro
|
|
416
|
-
trustClass: "
|
|
431
|
+
conversationId: "conv-auto-retro",
|
|
432
|
+
trustClass: "guardian",
|
|
417
433
|
});
|
|
418
434
|
|
|
419
435
|
disposeConversation(ctx);
|
|
420
436
|
|
|
421
|
-
// The outer trust-class guard in disposeConversation gates ALL three
|
|
422
|
-
// enqueues (graph_extract, auto-analyze, memory-retrospective). When
|
|
423
|
-
// the actor is untrusted, none of them fire.
|
|
424
437
|
expect(memoryRetroCalls).toHaveLength(0);
|
|
425
|
-
|
|
438
|
+
// graph_extract is also recursion-guarded by the same `!isAutoAnalysis`
|
|
439
|
+
// block, so it should be skipped here too.
|
|
440
|
+
expect(memoryJobCalls).toHaveLength(0);
|
|
426
441
|
});
|
|
427
442
|
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `config.tools.exclude` filter applied inside
|
|
3
|
+
* `createResolveToolsCallback`. Excluded tool names must not appear in the
|
|
4
|
+
* tool list resolved per turn, nor in the executor's `allowedToolNames`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
8
|
+
|
|
9
|
+
import * as configLoader from "../../config/loader.js";
|
|
10
|
+
import type { AssistantConfig } from "../../config/schema.js";
|
|
11
|
+
import type { ToolDefinition } from "../../providers/types.js";
|
|
12
|
+
import {
|
|
13
|
+
__clearRegistryForTesting,
|
|
14
|
+
registerMcpTools,
|
|
15
|
+
} from "../../tools/registry.js";
|
|
16
|
+
import type { Tool } from "../../tools/types.js";
|
|
17
|
+
import { createResolveToolsCallback } from "../conversation-tool-setup.js";
|
|
18
|
+
|
|
19
|
+
type SkillProjectionContext =
|
|
20
|
+
import("../conversation-tool-setup.js").SkillProjectionContext;
|
|
21
|
+
type SkillProjectionCache =
|
|
22
|
+
import("../conversation-skill-tools.js").SkillProjectionCache;
|
|
23
|
+
|
|
24
|
+
function def(name: string): ToolDefinition {
|
|
25
|
+
return { name, description: name, input_schema: { type: "object" } };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function mcpTool(name: string): Tool {
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
description: name,
|
|
32
|
+
origin: "mcp",
|
|
33
|
+
getDefinition: () => def(name),
|
|
34
|
+
} as unknown as Tool;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function makeCtx(
|
|
38
|
+
overrides: Partial<SkillProjectionContext> = {},
|
|
39
|
+
): SkillProjectionContext {
|
|
40
|
+
return {
|
|
41
|
+
skillProjectionState: new Map(),
|
|
42
|
+
skillProjectionCache: { fingerprints: new Map() } as SkillProjectionCache,
|
|
43
|
+
coreToolNames: new Set<string>(),
|
|
44
|
+
toolsDisabledDepth: 0,
|
|
45
|
+
...overrides,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function withExclude(exclude: string[]) {
|
|
50
|
+
const stub: Partial<AssistantConfig> = { tools: { exclude } };
|
|
51
|
+
return spyOn(configLoader, "getConfig").mockReturnValue(
|
|
52
|
+
stub as AssistantConfig,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let getConfigSpy: ReturnType<typeof withExclude> | undefined;
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
__clearRegistryForTesting();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
getConfigSpy?.mockRestore();
|
|
64
|
+
getConfigSpy = undefined;
|
|
65
|
+
__clearRegistryForTesting();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("createResolveToolsCallback — config.tools.exclude", () => {
|
|
69
|
+
test("excluded core tool is omitted from the resolved tool list", () => {
|
|
70
|
+
getConfigSpy = withExclude(["bash"]);
|
|
71
|
+
const resolver = createResolveToolsCallback(
|
|
72
|
+
[def("bash"), def("file_read")],
|
|
73
|
+
makeCtx(),
|
|
74
|
+
);
|
|
75
|
+
const result = resolver!([]);
|
|
76
|
+
expect(result.map((d) => d.name)).toEqual(["file_read"]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("excluded core tool is removed from ctx.allowedToolNames", () => {
|
|
80
|
+
getConfigSpy = withExclude(["bash"]);
|
|
81
|
+
const ctx = makeCtx();
|
|
82
|
+
const resolver = createResolveToolsCallback(
|
|
83
|
+
[def("bash"), def("file_read")],
|
|
84
|
+
ctx,
|
|
85
|
+
);
|
|
86
|
+
resolver!([]);
|
|
87
|
+
expect(ctx.allowedToolNames?.has("bash")).toBe(false);
|
|
88
|
+
expect(ctx.allowedToolNames?.has("file_read")).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("excluded MCP tool is omitted from the resolved tool list", () => {
|
|
92
|
+
registerMcpTools([
|
|
93
|
+
mcpTool("mcp__server__navigate"),
|
|
94
|
+
mcpTool("mcp__server__click"),
|
|
95
|
+
]);
|
|
96
|
+
getConfigSpy = withExclude(["mcp__server__navigate"]);
|
|
97
|
+
const resolver = createResolveToolsCallback(
|
|
98
|
+
[def("mcp__server__navigate"), def("mcp__server__click")],
|
|
99
|
+
makeCtx(),
|
|
100
|
+
);
|
|
101
|
+
const result = resolver!([]);
|
|
102
|
+
expect(result.map((d) => d.name)).toEqual(["mcp__server__click"]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("unknown name in exclude list is silently ignored", () => {
|
|
106
|
+
getConfigSpy = withExclude(["does_not_exist"]);
|
|
107
|
+
const resolver = createResolveToolsCallback([def("file_read")], makeCtx());
|
|
108
|
+
expect(() => resolver!([])).not.toThrow();
|
|
109
|
+
expect(resolver!([]).map((d) => d.name)).toEqual(["file_read"]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("empty exclude list leaves the tool set unchanged", () => {
|
|
113
|
+
getConfigSpy = withExclude([]);
|
|
114
|
+
const resolver = createResolveToolsCallback(
|
|
115
|
+
[def("bash"), def("file_read")],
|
|
116
|
+
makeCtx(),
|
|
117
|
+
);
|
|
118
|
+
expect(
|
|
119
|
+
resolver!([])
|
|
120
|
+
.map((d) => d.name)
|
|
121
|
+
.sort(),
|
|
122
|
+
).toEqual(["bash", "file_read"]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("excluded tool stays excluded under disk-pressure cleanup mode", () => {
|
|
126
|
+
// `bash` is a cleanup-safe tool and would normally survive cleanup mode;
|
|
127
|
+
// the exclude filter must still suppress it.
|
|
128
|
+
getConfigSpy = withExclude(["bash"]);
|
|
129
|
+
const ctx = makeCtx({ diskPressureCleanupModeActive: true });
|
|
130
|
+
const resolver = createResolveToolsCallback(
|
|
131
|
+
[def("bash"), def("file_read")],
|
|
132
|
+
ctx,
|
|
133
|
+
);
|
|
134
|
+
const result = resolver!([]);
|
|
135
|
+
expect(result.map((d) => d.name)).not.toContain("bash");
|
|
136
|
+
expect(ctx.allowedToolNames?.has("bash")).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
});
|