@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.2
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/bun.lock +0 -20
- package/docs/workspace-tools.md +33 -42
- package/eslint-rules/cli-no-daemon-internals.js +0 -6
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
- package/openapi.yaml +0 -155
- package/package.json +1 -4
- package/scripts/test.sh +15 -36
- package/src/__tests__/actor-token-service.test.ts +14 -36
- package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
- package/src/__tests__/annotate-risk-options.test.ts +0 -2
- package/src/__tests__/approval-cascade.test.ts +0 -2
- package/src/__tests__/assistant-attachments.test.ts +0 -42
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -2
- package/src/__tests__/build-persisted-content.test.ts +0 -2
- package/src/__tests__/call-controller.test.ts +0 -19
- package/src/__tests__/channel-guardian.test.ts +58 -94
- package/src/__tests__/channel-reply-delivery.test.ts +0 -2
- package/src/__tests__/compaction-events.test.ts +0 -2
- package/src/__tests__/compaction.benchmark.test.ts +0 -2
- package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
- package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
- package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
- package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
- package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
- package/src/__tests__/config-loader-backfill.test.ts +10 -123
- package/src/__tests__/config-schema.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
- package/src/__tests__/contacts-relay-reads.test.ts +15 -13
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +0 -134
- package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
- package/src/__tests__/conversation-history-web-search.test.ts +0 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -2
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
- package/src/__tests__/conversation-process-callsite.test.ts +0 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
- package/src/__tests__/conversation-queue.test.ts +0 -91
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
- package/src/__tests__/conversation-slash-queue.test.ts +0 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
- package/src/__tests__/conversation-speed-override.test.ts +0 -2
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
- package/src/__tests__/conversation-title-service.test.ts +0 -2
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-migration-rollback.test.ts +171 -205
- package/src/__tests__/db-test-helpers.ts +4 -5
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
- package/src/__tests__/disk-pressure-guard.test.ts +0 -41
- package/src/__tests__/dm-persistence.test.ts +0 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
- package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
- package/src/__tests__/exploration-drift-hook.test.ts +2 -3
- package/src/__tests__/filing-service.test.ts +0 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
- package/src/__tests__/guardian-dispatch.test.ts +1 -95
- package/src/__tests__/guardian-outbound-http.test.ts +0 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
- package/src/__tests__/heartbeat-service.test.ts +0 -2
- package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
- package/src/__tests__/host-app-control-routes.test.ts +30 -24
- package/src/__tests__/host-bash-routes.test.ts +41 -31
- package/src/__tests__/host-browser-routes.test.ts +32 -26
- package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
- package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
- package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
- package/src/__tests__/http-user-message-parity.test.ts +8 -290
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
- package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/invite-redemption-service.test.ts +0 -198
- package/src/__tests__/llm-context-normalization.test.ts +0 -105
- package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
- package/src/__tests__/llm-usage-store.test.ts +0 -25
- package/src/__tests__/mcp-health-check.test.ts +1 -2
- package/src/__tests__/media-stream-server-integration.test.ts +0 -127
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
- package/src/__tests__/messaging-send-tool.test.ts +0 -2
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +5 -146
- package/src/__tests__/native-web-search.test.ts +0 -2
- package/src/__tests__/non-member-access-request.test.ts +17 -189
- package/src/__tests__/notification-broadcaster.test.ts +0 -4
- package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
- package/src/__tests__/notification-deep-link.test.ts +0 -6
- package/src/__tests__/notification-guardian-path.test.ts +0 -19
- package/src/__tests__/openai-provider.test.ts +12 -22
- package/src/__tests__/openai-responses-provider.test.ts +2 -12
- package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
- package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
- package/src/__tests__/plugin-bootstrap.test.ts +73 -3
- package/src/__tests__/plugin-route-contribution.test.ts +17 -4
- package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
- package/src/__tests__/plugin-types.test.ts +2 -0
- package/src/__tests__/process-message-background-slack.test.ts +0 -2
- package/src/__tests__/process-message-display-content.test.ts +0 -2
- package/src/__tests__/provider-error-scenarios.test.ts +4 -5
- package/src/__tests__/provider-usage-tracking.test.ts +0 -39
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -4
- package/src/__tests__/relay-server.test.ts +25 -694
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -14
- package/src/__tests__/send-endpoint-busy.test.ts +8 -30
- package/src/__tests__/skills.test.ts +0 -44
- package/src/__tests__/slack-inbound-verification.test.ts +2 -47
- package/src/__tests__/stt-hints.test.ts +13 -44
- package/src/__tests__/subagent-detail.test.ts +0 -27
- package/src/__tests__/subagent-disposal.test.ts +0 -65
- package/src/__tests__/subagent-notify-parent.test.ts +0 -2
- package/src/__tests__/subagent-role-registry.test.ts +2 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +0 -2
- package/src/__tests__/suggestion-routes.test.ts +0 -2
- package/src/__tests__/title-generate-hook.test.ts +0 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
- package/src/__tests__/tool-executor.test.ts +11 -16
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
- package/src/__tests__/tool-start-timestamp.test.ts +0 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +0 -96
- package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -33
- package/src/__tests__/web-search-backend-failure.test.ts +0 -2
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
- package/src/__tests__/workspace-tool-loader.test.ts +2 -195
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +0 -56
- package/src/api/index.ts +1 -19
- package/src/api/responses/llm-request-log-entry.ts +0 -29
- package/src/api/responses/subagent-detail.ts +0 -17
- package/src/api/surfaces.ts +3 -39
- package/src/approvals/guardian-request-resolvers.ts +11 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +8 -10
- package/src/calls/inbound-trust-reader.ts +1 -17
- package/src/calls/media-stream-server.ts +0 -21
- package/src/calls/relay-server.ts +50 -167
- package/src/calls/relay-setup-router.ts +7 -37
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +12 -9
- package/src/calls/twilio-routes.ts +4 -14
- package/src/channels/types.ts +20 -10
- package/src/cli/commands/__tests__/cache.test.ts +1 -8
- package/src/cli/commands/cache.ts +181 -194
- package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
- package/src/cli/commands/db/status.ts +1 -37
- package/src/cli/commands/mcp.ts +218 -252
- package/src/cli/commands/memory/index.ts +0 -2
- package/src/cli/commands/plugins.ts +3 -75
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
- package/src/cli/lib/list-installed-plugins.ts +1 -179
- package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
- package/src/config/bundled-skills/subagent/SKILL.md +1 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +5 -38
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
- package/src/config/schemas/memory-lifecycle.ts +0 -12
- package/src/config/schemas/memory-v3.ts +0 -7
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/timeouts.ts +0 -8
- package/src/config/seed-inference-profiles.ts +11 -21
- package/src/config/skills.ts +5 -27
- package/src/config/sync-gated-profiles.ts +13 -12
- package/src/contacts/contacts-write.ts +0 -3
- package/src/daemon/assistant-attachments.ts +4 -27
- package/src/daemon/conversation-agent-loop.ts +0 -28
- package/src/daemon/conversation-process.ts +16 -35
- package/src/daemon/conversation-surfaces.ts +38 -111
- package/src/daemon/conversation-tool-setup.ts +16 -50
- package/src/daemon/conversation.ts +1 -13
- package/src/daemon/disk-pressure-guard.ts +2 -12
- package/src/daemon/event-loop-watchdog.ts +1 -28
- package/src/daemon/external-plugins-bootstrap.ts +34 -4
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
- package/src/daemon/handlers/config-a2a.ts +14 -6
- package/src/daemon/handlers/config-channels.ts +22 -78
- package/src/daemon/handlers/conversations.ts +0 -77
- package/src/daemon/lifecycle.ts +0 -4
- package/src/daemon/mcp-reload-service.ts +0 -10
- package/src/daemon/memory-v2-startup.test.ts +0 -72
- package/src/daemon/memory-v2-startup.ts +19 -87
- package/src/daemon/message-types/conversations.ts +0 -2
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +4 -0
- package/src/daemon/shutdown-handlers.ts +0 -20
- package/src/daemon/tool-setup-types.ts +0 -9
- package/src/daemon/workspace-tools-watcher.ts +328 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/client.ts +1 -15
- package/src/mcp/mcp-auth-orchestrator.ts +1 -6
- package/src/mcp/mcp-oauth-provider.ts +8 -19
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
- package/src/memory/conversation-crud.ts +0 -38
- package/src/memory/db-connection.ts +3 -22
- package/src/memory/db-init.ts +502 -36
- package/src/memory/db-singleton.ts +4 -6
- package/src/memory/jobs-worker.ts +0 -58
- package/src/memory/llm-request-log-store.ts +1 -26
- package/src/memory/llm-usage-store.ts +20 -48
- package/src/memory/memory-retrospective-job.ts +8 -9
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/registry.ts +573 -0
- package/src/memory/migrations/run-migrations.ts +6 -90
- package/src/memory/migrations/validate-migration-state.ts +66 -101
- package/src/memory/schema/conversations.ts +0 -9
- package/src/memory/schema/infrastructure.ts +0 -20
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
- package/src/memory/v2/cli-command-store.ts +38 -75
- package/src/memory/v2/prompts/consolidation.ts +82 -13
- package/src/memory/v2/prompts/router.ts +93 -21
- package/src/memory/v2/skill-store.ts +31 -68
- package/src/notifications/__tests__/broadcaster.test.ts +8 -16
- package/src/notifications/__tests__/decision-engine.test.ts +9 -78
- package/src/notifications/broadcaster.ts +1 -8
- package/src/notifications/decision-engine.ts +7 -15
- package/src/notifications/destination-resolver.ts +24 -68
- package/src/notifications/emit-signal.ts +14 -39
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +4 -7
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +5 -3
- package/src/plugin-api/vision-support.test.ts +4 -28
- package/src/plugin-api/vision-support.ts +31 -66
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
- package/src/plugins/defaults/advisor/consult.ts +6 -110
- package/src/plugins/defaults/advisor/steering.ts +2 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
- package/src/plugins/mtime-cache.ts +291 -76
- package/src/plugins/pipeline.ts +13 -111
- package/src/plugins/types.ts +2 -0
- package/src/providers/anthropic/client.ts +0 -5
- package/src/providers/call-site-routing.ts +0 -4
- package/src/providers/model-catalog.ts +0 -16
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/chat-completions-provider.ts +83 -37
- package/src/providers/openai/responses-provider.ts +46 -50
- package/src/providers/openrouter/client.ts +0 -5
- package/src/providers/provider-send-message.ts +0 -4
- package/src/providers/ratelimit.ts +0 -4
- package/src/providers/retry.ts +0 -4
- package/src/providers/types.ts +0 -9
- package/src/providers/usage-tracking.ts +0 -4
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
- package/src/runtime/access-request-helper.ts +39 -19
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +2 -9
- package/src/runtime/auth/require-bound-guardian.ts +11 -21
- package/src/runtime/channel-verification-service.ts +31 -56
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +7 -66
- package/src/runtime/invite-redemption-service.ts +187 -198
- package/src/runtime/local-actor-identity.ts +11 -76
- package/src/runtime/pending-interactions.ts +1 -11
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +32 -8
- package/src/runtime/routes/conversation-cli-routes.ts +5 -4
- package/src/runtime/routes/conversation-list-routes.ts +7 -4
- package/src/runtime/routes/conversation-query-routes.ts +0 -72
- package/src/runtime/routes/conversation-routes.ts +85 -84
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -3
- package/src/runtime/routes/guardian-action-routes.ts +5 -4
- package/src/runtime/routes/host-app-control-routes.ts +4 -5
- package/src/runtime/routes/host-bash-routes.ts +4 -5
- package/src/runtime/routes/host-browser-routes.ts +11 -9
- package/src/runtime/routes/host-cu-routes.ts +4 -5
- package/src/runtime/routes/host-file-routes.ts +4 -5
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +2 -3
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/llm-context-normalization.ts +0 -83
- package/src/runtime/routes/mcp-auth-routes.ts +19 -171
- package/src/runtime/routes/migration-rollback-routes.ts +3 -4
- package/src/runtime/routes/migration-routes.ts +1 -4
- package/src/runtime/routes/subagents-routes.ts +0 -5
- package/src/runtime/routes/surface-action-routes.ts +56 -42
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
- package/src/runtime/services/conversation-serializer.ts +9 -7
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +9 -85
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +0 -16
- package/src/subagent/manager.ts +0 -9
- package/src/subagent/types.ts +3 -3
- package/src/telemetry/types.ts +1 -34
- package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
- package/src/telemetry/usage-telemetry-reporter.ts +3 -87
- package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
- package/src/tools/ask-question/ask-question-tool.ts +0 -13
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +0 -18
- package/src/tools/shared/filesystem/path-policy.ts +5 -12
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +2 -9
- package/src/tools/tool-manifest.ts +0 -3
- package/src/tools/types.ts +2 -17
- package/src/tools/workspace-tools/loader.ts +244 -348
- package/src/util/errors.ts +1 -26
- package/src/util/platform.ts +0 -5
- package/src/workflows/library.test.ts +0 -140
- package/src/workflows/library.ts +28 -82
- package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
- package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
- package/src/__tests__/code-search-tool.test.ts +0 -585
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
- package/src/__tests__/plugin-pipeline.test.ts +0 -96
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
- package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
- package/src/agent/loop-exclusive-tool.test.ts +0 -150
- package/src/api/constants/sse-replay.ts +0 -41
- package/src/api/events/conversation-notice.ts +0 -26
- package/src/approvals/guardian-channel-delivery.ts +0 -30
- package/src/approvals/guardian-expiry-notifier.ts +0 -148
- package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
- package/src/cli/commands/memory/worker.ts +0 -175
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
- package/src/config/prune-seeded-callsite-defaults.ts +0 -110
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
- package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
- package/src/contacts/guardian-delivery-reader.ts +0 -223
- package/src/contacts/member-write-relay.ts +0 -189
- package/src/daemon/conversation-notices.ts +0 -60
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
- package/src/hooks/hook-loader.ts +0 -341
- package/src/mcp/mcp-header-store.ts +0 -134
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
- package/src/memory/prompt-override.ts +0 -129
- package/src/memory/steps.ts +0 -573
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -118
- package/src/memory/worker-process.ts +0 -72
- package/src/notifications/__tests__/connected-channels.test.ts +0 -114
- package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
- package/src/onboarding/checkin-event.test.ts +0 -222
- package/src/onboarding/checkin-event.ts +0 -321
- package/src/onboarding/schedule-checkin.ts +0 -190
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/surface-import.ts +0 -121
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
- package/src/providers/openai/api-error-normalization.ts +0 -270
- package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
- package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
- package/src/runtime/anchored-guardian.test.ts +0 -156
- package/src/runtime/anchored-guardian.ts +0 -135
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
- package/src/runtime/local-principal-trust.ts +0 -52
- package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
- package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
- package/src/tools/filesystem/search.ts +0 -543
- package/src/util/telemetry-db-path.ts +0 -24
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
2
|
-
import { v4 as uuid } from "uuid";
|
|
3
|
-
|
|
4
|
-
import { getCachedShareAnalytics } from "../platform/consent-cache.js";
|
|
5
|
-
import { getTelemetryDb } from "./db-connection.js";
|
|
6
|
-
import { watchdogEvents } from "./schema.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Input for one `watchdog` telemetry event. Metadata only — never conversation
|
|
10
|
-
* content. `value` and `detail` are optional; omitting both yields the minimal
|
|
11
|
-
* event (check_name only). `detail` is a JSON bag serialized to text on persist
|
|
12
|
-
* and forwarded verbatim on flush.
|
|
13
|
-
*/
|
|
14
|
-
export interface WatchdogEventRecord {
|
|
15
|
-
checkName: string;
|
|
16
|
-
/** Measured magnitude (block ms, idle ms, ...). Null when the check carries no scalar. */
|
|
17
|
-
value?: number | null;
|
|
18
|
-
/** Open JSON bag for extra fields (reason codes, secondary numbers, ...). */
|
|
19
|
-
detail?: Record<string, unknown> | null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** A persisted watchdog event row. */
|
|
23
|
-
export interface WatchdogEvent {
|
|
24
|
-
id: string;
|
|
25
|
-
createdAt: number;
|
|
26
|
-
checkName: string;
|
|
27
|
-
value: number | null;
|
|
28
|
-
/** Raw `detail` JSON text from the row, or null. Parsed by the reporter on flush. */
|
|
29
|
-
detail: string | null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Record a `watchdog` telemetry event for a watchdog check firing. No-ops when
|
|
34
|
-
* usage data collection is disabled (the event is dropped to honor the opt-out,
|
|
35
|
-
* matching the rest of telemetry) — so opt-out rows never exist and the
|
|
36
|
-
* reporter's standard 0 watermark default is safe.
|
|
37
|
-
*/
|
|
38
|
-
export function recordWatchdogEvent(record: WatchdogEventRecord): void {
|
|
39
|
-
if (!getCachedShareAnalytics()) return;
|
|
40
|
-
const db = getTelemetryDb();
|
|
41
|
-
if (!db) return;
|
|
42
|
-
db.insert(watchdogEvents)
|
|
43
|
-
.values({
|
|
44
|
-
id: uuid(),
|
|
45
|
-
createdAt: Date.now(),
|
|
46
|
-
checkName: record.checkName,
|
|
47
|
-
value: record.value ?? null,
|
|
48
|
-
detail: record.detail != null ? JSON.stringify(record.detail) : null,
|
|
49
|
-
})
|
|
50
|
-
.run();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Query watchdog events that haven't been reported to telemetry yet.
|
|
55
|
-
* Uses a compound cursor (createdAt + id) for reliable watermarking.
|
|
56
|
-
*/
|
|
57
|
-
export function queryUnreportedWatchdogEvents(
|
|
58
|
-
afterCreatedAt: number,
|
|
59
|
-
afterId: string | undefined,
|
|
60
|
-
limit: number,
|
|
61
|
-
): WatchdogEvent[] {
|
|
62
|
-
const db = getTelemetryDb();
|
|
63
|
-
if (!db) return [];
|
|
64
|
-
return db
|
|
65
|
-
.select({
|
|
66
|
-
id: watchdogEvents.id,
|
|
67
|
-
createdAt: watchdogEvents.createdAt,
|
|
68
|
-
checkName: watchdogEvents.checkName,
|
|
69
|
-
value: watchdogEvents.value,
|
|
70
|
-
detail: watchdogEvents.detail,
|
|
71
|
-
})
|
|
72
|
-
.from(watchdogEvents)
|
|
73
|
-
.where(
|
|
74
|
-
afterId
|
|
75
|
-
? or(
|
|
76
|
-
gt(watchdogEvents.createdAt, afterCreatedAt),
|
|
77
|
-
and(
|
|
78
|
-
eq(watchdogEvents.createdAt, afterCreatedAt),
|
|
79
|
-
gt(watchdogEvents.id, afterId),
|
|
80
|
-
),
|
|
81
|
-
)
|
|
82
|
-
: gt(watchdogEvents.createdAt, afterCreatedAt),
|
|
83
|
-
)
|
|
84
|
-
.orderBy(asc(watchdogEvents.createdAt), asc(watchdogEvents.id))
|
|
85
|
-
.limit(limit)
|
|
86
|
-
.all();
|
|
87
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared control surface for the memory jobs worker *process* — the detached
|
|
3
|
-
* OS process whose entry point is `worker-process.ts`.
|
|
4
|
-
*
|
|
5
|
-
* Both the `assistant memory worker` CLI and the daemon lifecycle (when
|
|
6
|
-
* `memory.worker.enabled` is set) need to probe, spawn, and stop this process,
|
|
7
|
-
* so the PID-file bookkeeping lives here in one place.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
11
|
-
|
|
12
|
-
import { getMemoryWorkerPidPath } from "../util/platform.js";
|
|
13
|
-
|
|
14
|
-
export interface MemoryWorkerStatus {
|
|
15
|
-
status: "running" | "not_running";
|
|
16
|
-
pid?: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Inspect the PID file to determine whether the worker process is alive.
|
|
21
|
-
* A stale PID file (pointing at a dead process) is cleaned up and reported
|
|
22
|
-
* as not_running.
|
|
23
|
-
*/
|
|
24
|
-
export function probeMemoryWorker(): MemoryWorkerStatus {
|
|
25
|
-
const pidPath = getMemoryWorkerPidPath();
|
|
26
|
-
if (!existsSync(pidPath)) return { status: "not_running" };
|
|
27
|
-
|
|
28
|
-
const raw = readFileSync(pidPath, "utf-8").trim();
|
|
29
|
-
const pid = parseInt(raw, 10);
|
|
30
|
-
if (!Number.isFinite(pid) || pid <= 0) return { status: "not_running" };
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
process.kill(pid, 0);
|
|
34
|
-
return { status: "running", pid };
|
|
35
|
-
} catch (err: unknown) {
|
|
36
|
-
if (
|
|
37
|
-
err &&
|
|
38
|
-
typeof err === "object" &&
|
|
39
|
-
"code" in err &&
|
|
40
|
-
err.code === "ESRCH"
|
|
41
|
-
) {
|
|
42
|
-
// Stale PID file — clean it up.
|
|
43
|
-
try {
|
|
44
|
-
unlinkSync(pidPath);
|
|
45
|
-
} catch {
|
|
46
|
-
// best-effort
|
|
47
|
-
}
|
|
48
|
-
return { status: "not_running" };
|
|
49
|
-
}
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export class MemoryWorkerSpawnError extends Error {}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Spawn the memory worker as a detached background process.
|
|
58
|
-
*
|
|
59
|
-
* If a worker is already running, returns its PID with `alreadyRunning: true`
|
|
60
|
-
* rather than spawning a second one. Throws {@link MemoryWorkerSpawnError} if
|
|
61
|
-
* the child is spawned but never writes its PID file (i.e. failed to start).
|
|
62
|
-
*/
|
|
63
|
-
export async function spawnMemoryWorkerProcess(): Promise<{
|
|
64
|
-
pid: number;
|
|
65
|
-
alreadyRunning: boolean;
|
|
66
|
-
}> {
|
|
67
|
-
const current = probeMemoryWorker();
|
|
68
|
-
if (current.status === "running" && current.pid != null) {
|
|
69
|
-
return { pid: current.pid, alreadyRunning: true };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const pidPath = getMemoryWorkerPidPath();
|
|
73
|
-
const entry = new URL("./worker-process.ts", import.meta.url);
|
|
74
|
-
|
|
75
|
-
// Spawn detached so the worker survives the spawning process exiting.
|
|
76
|
-
const child = Bun.spawn({
|
|
77
|
-
cmd: ["bun", "run", entry.pathname],
|
|
78
|
-
stdio: ["ignore", "ignore", "ignore"],
|
|
79
|
-
detached: true,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Unreference so the spawning process doesn't wait for the child.
|
|
83
|
-
child.unref();
|
|
84
|
-
|
|
85
|
-
// Wait briefly for the PID file to appear (the worker writes it on startup).
|
|
86
|
-
let pidWritten = false;
|
|
87
|
-
for (let i = 0; i < 10; i++) {
|
|
88
|
-
await Bun.sleep(100);
|
|
89
|
-
if (existsSync(pidPath)) {
|
|
90
|
-
pidWritten = true;
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (!pidWritten) {
|
|
96
|
-
throw new MemoryWorkerSpawnError(
|
|
97
|
-
"Memory worker was spawned but PID file did not appear within 1s",
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
102
|
-
return { pid, alreadyRunning: false };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Send SIGTERM to the worker process if it is actually running.
|
|
107
|
-
*
|
|
108
|
-
* Returns the status observed before signalling, so callers can report
|
|
109
|
-
* whether anything was stopped. Only throws if `process.kill` itself fails
|
|
110
|
-
* (e.g. EPERM) — a not-running worker is a no-op.
|
|
111
|
-
*/
|
|
112
|
-
export function stopMemoryWorkerProcess(): MemoryWorkerStatus {
|
|
113
|
-
const current = probeMemoryWorker();
|
|
114
|
-
if (current.status === "running" && current.pid != null) {
|
|
115
|
-
process.kill(current.pid, "SIGTERM");
|
|
116
|
-
}
|
|
117
|
-
return current;
|
|
118
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standalone entry point for the memory jobs worker as its own OS process.
|
|
3
|
-
*
|
|
4
|
-
* Spawned by `assistant memory worker start`. Loads config, starts the
|
|
5
|
-
* worker loop, writes a PID file, and stays alive until SIGTERM/SIGINT.
|
|
6
|
-
*
|
|
7
|
-
* The worker's internal `setTimeout` calls `.unref()`, which is correct
|
|
8
|
-
* inside the daemon (don't keep the daemon alive for the worker) but would
|
|
9
|
-
* cause this standalone process to exit immediately. A ref'd keep-alive
|
|
10
|
-
* interval prevents that.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
14
|
-
|
|
15
|
-
import { getConfig } from "../config/loader.js";
|
|
16
|
-
import { getLogger } from "../util/logger.js";
|
|
17
|
-
import { getMemoryWorkerPidPath } from "../util/platform.js";
|
|
18
|
-
import { startInProcessMemoryJobsWorker } from "./jobs-worker.js";
|
|
19
|
-
|
|
20
|
-
const log = getLogger("memory-worker-process");
|
|
21
|
-
|
|
22
|
-
function cleanupPidFile(): void {
|
|
23
|
-
const pidPath = getMemoryWorkerPidPath();
|
|
24
|
-
try {
|
|
25
|
-
if (existsSync(pidPath)) unlinkSync(pidPath);
|
|
26
|
-
} catch {
|
|
27
|
-
// best-effort
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function main(): Promise<void> {
|
|
32
|
-
const config = getConfig();
|
|
33
|
-
const pidPath = getMemoryWorkerPidPath();
|
|
34
|
-
|
|
35
|
-
if (config.memory.enabled === false) {
|
|
36
|
-
log.info("Memory is disabled in config; worker process exiting");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Write PID file so `status` and `stop` can find us.
|
|
41
|
-
writeFileSync(pidPath, String(process.pid), { flag: "w" });
|
|
42
|
-
log.info({ pid: process.pid, pidPath }, "Memory worker process started");
|
|
43
|
-
|
|
44
|
-
const worker = startInProcessMemoryJobsWorker();
|
|
45
|
-
|
|
46
|
-
// Keep-alive: the worker's setTimeout timers are unref'd, so without
|
|
47
|
-
// this interval the process would exit immediately.
|
|
48
|
-
const keepAlive = setInterval(() => {}, 60_000);
|
|
49
|
-
|
|
50
|
-
const shutdown = (signal: string) => {
|
|
51
|
-
log.info({ signal }, "Memory worker process shutting down");
|
|
52
|
-
worker.stop();
|
|
53
|
-
clearInterval(keepAlive);
|
|
54
|
-
cleanupPidFile();
|
|
55
|
-
process.exit(0);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
59
|
-
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
60
|
-
|
|
61
|
-
// Clean up if the process exits unexpectedly through any other path.
|
|
62
|
-
process.on("exit", () => {
|
|
63
|
-
worker.stop();
|
|
64
|
-
cleanupPidFile();
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
void main().catch((err) => {
|
|
69
|
-
log.error({ err }, "Memory worker process failed to start");
|
|
70
|
-
cleanupPidFile();
|
|
71
|
-
process.exit(1);
|
|
72
|
-
});
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for getConnectedChannels connectivity resolution.
|
|
3
|
-
*
|
|
4
|
-
* Connectivity must mirror destination-resolver's `resolveGuardian`:
|
|
5
|
-
* gateway-first, with a LOCAL contacts fallback on ANY per-channel no-match
|
|
6
|
-
* (gateway list null OR no active gateway entry for the channel). This keeps a
|
|
7
|
-
* channel from being marked connected when it can't be delivered (and
|
|
8
|
-
* vice-versa).
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
12
|
-
|
|
13
|
-
import type { GuardianDelivery } from "@vellumai/gateway-client";
|
|
14
|
-
|
|
15
|
-
mock.module("../../util/logger.js", () => ({
|
|
16
|
-
getLogger: () =>
|
|
17
|
-
new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
|
|
18
|
-
truncateForLog: (value: string) => value,
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
let deliverableChannels: string[] = [];
|
|
22
|
-
let gatewayGuardians: GuardianDelivery[] | null = null;
|
|
23
|
-
let localChatId: string | null = null;
|
|
24
|
-
|
|
25
|
-
const realConfig = await import("../../channels/config.js");
|
|
26
|
-
|
|
27
|
-
mock.module("../../channels/config.js", () => ({
|
|
28
|
-
...realConfig,
|
|
29
|
-
getDeliverableChannels: () => deliverableChannels,
|
|
30
|
-
}));
|
|
31
|
-
|
|
32
|
-
const realReader = await import("../../contacts/guardian-delivery-reader.js");
|
|
33
|
-
|
|
34
|
-
mock.module("../../contacts/guardian-delivery-reader.js", () => ({
|
|
35
|
-
...realReader,
|
|
36
|
-
getGuardianDelivery: async () => gatewayGuardians,
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
|
-
const realContactStore = await import("../../contacts/contact-store.js");
|
|
40
|
-
|
|
41
|
-
mock.module("../../contacts/contact-store.js", () => ({
|
|
42
|
-
...realContactStore,
|
|
43
|
-
findGuardianForChannel: (_channelType: string) =>
|
|
44
|
-
localChatId === null
|
|
45
|
-
? null
|
|
46
|
-
: { contact: { principalId: "p1" }, channel: { externalChatId: localChatId } },
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
const { getConnectedChannels } = await import("../emit-signal.js");
|
|
50
|
-
|
|
51
|
-
function gatewayBinding(channelType: string, externalChatId: string): GuardianDelivery {
|
|
52
|
-
return { channelType, contactId: "c1", address: "addr", externalChatId, status: "active" };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
deliverableChannels = [];
|
|
57
|
-
gatewayGuardians = null;
|
|
58
|
-
localChatId = null;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("getConnectedChannels gateway-first-then-local connectivity", () => {
|
|
62
|
-
test("marks telegram connected from a gateway-only binding", async () => {
|
|
63
|
-
deliverableChannels = ["telegram"];
|
|
64
|
-
gatewayGuardians = [gatewayBinding("telegram", "123")];
|
|
65
|
-
localChatId = null;
|
|
66
|
-
|
|
67
|
-
expect(await getConnectedChannels()).toContain("telegram");
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("falls back to a local binding when the gateway is unreachable (null)", async () => {
|
|
71
|
-
deliverableChannels = ["telegram"];
|
|
72
|
-
gatewayGuardians = null;
|
|
73
|
-
localChatId = "456";
|
|
74
|
-
|
|
75
|
-
expect(await getConnectedChannels()).toContain("telegram");
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("marks telegram disconnected when neither source has a binding", async () => {
|
|
79
|
-
deliverableChannels = ["telegram"];
|
|
80
|
-
gatewayGuardians = null;
|
|
81
|
-
localChatId = null;
|
|
82
|
-
|
|
83
|
-
expect(await getConnectedChannels()).not.toContain("telegram");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("falls back to local when the gateway responds without that channel", async () => {
|
|
87
|
-
// Gateway present but with no active telegram entry ⇒ per-channel no-match,
|
|
88
|
-
// so connectivity falls back to the local mirror (mirrors
|
|
89
|
-
// destination-resolver's per-channel fallback).
|
|
90
|
-
deliverableChannels = ["telegram"];
|
|
91
|
-
gatewayGuardians = [];
|
|
92
|
-
localChatId = "789";
|
|
93
|
-
|
|
94
|
-
expect(await getConnectedChannels()).toContain("telegram");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("only marks slack connected for D-prefixed (DM) chat IDs", async () => {
|
|
98
|
-
deliverableChannels = ["slack"];
|
|
99
|
-
gatewayGuardians = [gatewayBinding("slack", "C-public")];
|
|
100
|
-
expect(await getConnectedChannels()).not.toContain("slack");
|
|
101
|
-
|
|
102
|
-
gatewayGuardians = [gatewayBinding("slack", "D-dm")];
|
|
103
|
-
expect(await getConnectedChannels()).toContain("slack");
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test("always reports vellum and platform connected", async () => {
|
|
107
|
-
deliverableChannels = ["vellum", "platform"];
|
|
108
|
-
gatewayGuardians = null;
|
|
109
|
-
|
|
110
|
-
const connected = await getConnectedChannels();
|
|
111
|
-
expect(connected).toContain("vellum");
|
|
112
|
-
expect(connected).toContain("platform");
|
|
113
|
-
});
|
|
114
|
-
});
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Verifies resolveDestinations resolves guardian delivery endpoints from the
|
|
3
|
-
* gateway-provided guardian list, with shapes identical to the local read, and
|
|
4
|
-
* falls back to the local contacts read when the list is null.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
8
|
-
|
|
9
|
-
import type { GuardianDelivery } from "@vellumai/gateway-client";
|
|
10
|
-
|
|
11
|
-
mock.module("../../util/logger.js", () => ({
|
|
12
|
-
getLogger: () =>
|
|
13
|
-
new Proxy({} as Record<string, unknown>, {
|
|
14
|
-
get: () => () => {},
|
|
15
|
-
}),
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
// Local fallback read; mocked so the null-list path is deterministic.
|
|
19
|
-
let localGuardian:
|
|
20
|
-
| { contact: { principalId?: string }; channel: { address: string; externalChatId?: string } }
|
|
21
|
-
| null = null;
|
|
22
|
-
|
|
23
|
-
mock.module("../../contacts/contact-store.js", () => ({
|
|
24
|
-
findGuardianForChannel: (_channelType: string) => localGuardian,
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
const { resolveDestinations } = await import("../destination-resolver.js");
|
|
28
|
-
|
|
29
|
-
function guardian(
|
|
30
|
-
overrides: Partial<GuardianDelivery> & Pick<GuardianDelivery, "channelType" | "address">,
|
|
31
|
-
): GuardianDelivery {
|
|
32
|
-
return {
|
|
33
|
-
contactId: "contact-1",
|
|
34
|
-
status: "active",
|
|
35
|
-
...overrides,
|
|
36
|
-
} as GuardianDelivery;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
describe("resolveDestinations — gateway guardian list", () => {
|
|
40
|
-
beforeEach(() => {
|
|
41
|
-
localGuardian = null;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("vellum carries guardianPrincipalId from the gateway list", () => {
|
|
45
|
-
const list = [
|
|
46
|
-
guardian({ channelType: "vellum", address: "user@example.com", principalId: "prin-1" }),
|
|
47
|
-
];
|
|
48
|
-
const result = resolveDestinations(["vellum"], list);
|
|
49
|
-
expect(result.get("vellum")).toEqual({
|
|
50
|
-
channel: "vellum",
|
|
51
|
-
metadata: { guardianPrincipalId: "prin-1" },
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("platform carries guardianPrincipalId from the vellum guardian", () => {
|
|
56
|
-
const list = [
|
|
57
|
-
guardian({ channelType: "vellum", address: "user@example.com", principalId: "prin-1" }),
|
|
58
|
-
];
|
|
59
|
-
const result = resolveDestinations(["platform"], list);
|
|
60
|
-
expect(result.get("platform")).toEqual({
|
|
61
|
-
channel: "platform",
|
|
62
|
-
metadata: { guardianPrincipalId: "prin-1" },
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("telegram resolves endpoint and binding context", () => {
|
|
67
|
-
const list = [
|
|
68
|
-
guardian({
|
|
69
|
-
channelType: "telegram",
|
|
70
|
-
address: "tg-user",
|
|
71
|
-
externalChatId: "12345",
|
|
72
|
-
}),
|
|
73
|
-
];
|
|
74
|
-
const result = resolveDestinations(["telegram"], list);
|
|
75
|
-
expect(result.get("telegram")).toEqual({
|
|
76
|
-
channel: "telegram",
|
|
77
|
-
endpoint: "12345",
|
|
78
|
-
metadata: { externalUserId: "tg-user" },
|
|
79
|
-
bindingContext: {
|
|
80
|
-
sourceChannel: "telegram",
|
|
81
|
-
externalChatId: "12345",
|
|
82
|
-
externalUserId: "tg-user",
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("telegram without externalChatId is omitted", () => {
|
|
88
|
-
const list = [guardian({ channelType: "telegram", address: "tg-user" })];
|
|
89
|
-
const result = resolveDestinations(["telegram"], list);
|
|
90
|
-
expect(result.has("telegram")).toBe(false);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("slack resolves DM endpoint and binding context", () => {
|
|
94
|
-
const list = [
|
|
95
|
-
guardian({
|
|
96
|
-
channelType: "slack",
|
|
97
|
-
address: "slack-user",
|
|
98
|
-
externalChatId: "D123",
|
|
99
|
-
}),
|
|
100
|
-
];
|
|
101
|
-
const result = resolveDestinations(["slack"], list);
|
|
102
|
-
expect(result.get("slack")).toEqual({
|
|
103
|
-
channel: "slack",
|
|
104
|
-
endpoint: "D123",
|
|
105
|
-
metadata: { externalUserId: "slack-user" },
|
|
106
|
-
bindingContext: {
|
|
107
|
-
sourceChannel: "slack",
|
|
108
|
-
externalChatId: "D123",
|
|
109
|
-
externalUserId: "slack-user",
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test("slack non-DM channel is dropped", () => {
|
|
115
|
-
const list = [
|
|
116
|
-
guardian({
|
|
117
|
-
channelType: "slack",
|
|
118
|
-
address: "slack-user",
|
|
119
|
-
externalChatId: "C123",
|
|
120
|
-
}),
|
|
121
|
-
];
|
|
122
|
-
const result = resolveDestinations(["slack"], list);
|
|
123
|
-
expect(result.has("slack")).toBe(false);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
test("inactive guardian is ignored", () => {
|
|
127
|
-
const list = [
|
|
128
|
-
guardian({
|
|
129
|
-
channelType: "telegram",
|
|
130
|
-
address: "tg-user",
|
|
131
|
-
externalChatId: "12345",
|
|
132
|
-
status: "revoked",
|
|
133
|
-
}),
|
|
134
|
-
];
|
|
135
|
-
const result = resolveDestinations(["telegram"], list);
|
|
136
|
-
expect(result.has("telegram")).toBe(false);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
describe("resolveDestinations — null list falls back to local read", () => {
|
|
141
|
-
beforeEach(() => {
|
|
142
|
-
localGuardian = null;
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test("telegram resolves from the local contacts read", () => {
|
|
146
|
-
localGuardian = {
|
|
147
|
-
contact: {},
|
|
148
|
-
channel: { address: "tg-user", externalChatId: "12345" },
|
|
149
|
-
};
|
|
150
|
-
const result = resolveDestinations(["telegram"], null);
|
|
151
|
-
expect(result.get("telegram")).toEqual({
|
|
152
|
-
channel: "telegram",
|
|
153
|
-
endpoint: "12345",
|
|
154
|
-
metadata: { externalUserId: "tg-user" },
|
|
155
|
-
bindingContext: {
|
|
156
|
-
sourceChannel: "telegram",
|
|
157
|
-
externalChatId: "12345",
|
|
158
|
-
externalUserId: "tg-user",
|
|
159
|
-
},
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
test("slack DM resolves from the local contacts read", () => {
|
|
164
|
-
localGuardian = {
|
|
165
|
-
contact: {},
|
|
166
|
-
channel: { address: "slack-user", externalChatId: "D123" },
|
|
167
|
-
};
|
|
168
|
-
const result = resolveDestinations(["slack"], null);
|
|
169
|
-
expect(result.get("slack")).toEqual({
|
|
170
|
-
channel: "slack",
|
|
171
|
-
endpoint: "D123",
|
|
172
|
-
metadata: { externalUserId: "slack-user" },
|
|
173
|
-
bindingContext: {
|
|
174
|
-
sourceChannel: "slack",
|
|
175
|
-
externalChatId: "D123",
|
|
176
|
-
externalUserId: "slack-user",
|
|
177
|
-
},
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test("vellum carries principalId from the local contacts read", () => {
|
|
182
|
-
localGuardian = {
|
|
183
|
-
contact: { principalId: "prin-1" },
|
|
184
|
-
channel: { address: "user@example.com" },
|
|
185
|
-
};
|
|
186
|
-
const result = resolveDestinations(["vellum"], null);
|
|
187
|
-
expect(result.get("vellum")).toEqual({
|
|
188
|
-
channel: "vellum",
|
|
189
|
-
metadata: { guardianPrincipalId: "prin-1" },
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
describe("resolveDestinations — gateway yields no channel match falls back to local", () => {
|
|
195
|
-
beforeEach(() => {
|
|
196
|
-
localGuardian = null;
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("empty gateway list falls back to local telegram binding", () => {
|
|
200
|
-
localGuardian = {
|
|
201
|
-
contact: {},
|
|
202
|
-
channel: { address: "tg-user", externalChatId: "12345" },
|
|
203
|
-
};
|
|
204
|
-
const result = resolveDestinations(["telegram"], []);
|
|
205
|
-
expect(result.get("telegram")).toEqual({
|
|
206
|
-
channel: "telegram",
|
|
207
|
-
endpoint: "12345",
|
|
208
|
-
metadata: { externalUserId: "tg-user" },
|
|
209
|
-
bindingContext: {
|
|
210
|
-
sourceChannel: "telegram",
|
|
211
|
-
externalChatId: "12345",
|
|
212
|
-
externalUserId: "tg-user",
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
test("gateway list missing the channel falls back to local slack DM", () => {
|
|
218
|
-
localGuardian = {
|
|
219
|
-
contact: {},
|
|
220
|
-
channel: { address: "slack-user", externalChatId: "D123" },
|
|
221
|
-
};
|
|
222
|
-
// Gateway returns a telegram guardian but no slack entry.
|
|
223
|
-
const list = [
|
|
224
|
-
guardian({ channelType: "telegram", address: "tg", externalChatId: "999" }),
|
|
225
|
-
];
|
|
226
|
-
const result = resolveDestinations(["slack"], list);
|
|
227
|
-
expect(result.get("slack")).toEqual({
|
|
228
|
-
channel: "slack",
|
|
229
|
-
endpoint: "D123",
|
|
230
|
-
metadata: { externalUserId: "slack-user" },
|
|
231
|
-
bindingContext: {
|
|
232
|
-
sourceChannel: "slack",
|
|
233
|
-
externalChatId: "D123",
|
|
234
|
-
externalUserId: "slack-user",
|
|
235
|
-
},
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
test("empty gateway list falls back to local vellum principalId", () => {
|
|
240
|
-
localGuardian = {
|
|
241
|
-
contact: { principalId: "prin-1" },
|
|
242
|
-
channel: { address: "user@example.com" },
|
|
243
|
-
};
|
|
244
|
-
const result = resolveDestinations(["vellum"], []);
|
|
245
|
-
expect(result.get("vellum")).toEqual({
|
|
246
|
-
channel: "vellum",
|
|
247
|
-
metadata: { guardianPrincipalId: "prin-1" },
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test("empty gateway list with no local binding omits telegram", () => {
|
|
252
|
-
localGuardian = null;
|
|
253
|
-
const result = resolveDestinations(["telegram"], []);
|
|
254
|
-
expect(result.has("telegram")).toBe(false);
|
|
255
|
-
});
|
|
256
|
-
});
|