@vellumai/assistant 0.10.12-dev.202607250047.75b9ec6 → 0.10.12-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/trusted-contact-access.md +15 -29
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +1 -69
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +1 -69
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +1 -69
- package/openapi.yaml +7 -28
- package/package.json +1 -1
- package/src/__tests__/acp-session.test.ts +3 -3
- package/src/__tests__/approval-cascade.test.ts +5 -5
- package/src/__tests__/approval-routes-http.test.ts +3 -3
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
- package/src/__tests__/assistant-event-hub-targeted.test.ts +11 -13
- package/src/__tests__/assistant-event-hub.test.ts +11 -13
- package/src/__tests__/assistant-event.test.ts +9 -12
- package/src/__tests__/assistant-id-boundary-guard.test.ts +58 -0
- package/src/__tests__/assistant-stream-state.test.ts +3 -5
- package/src/__tests__/avatar-identity-sync.test.ts +3 -3
- package/src/__tests__/call-setup-flow-name-capture.test.ts +3 -65
- package/src/__tests__/channel-approvals.test.ts +27 -0
- package/src/__tests__/channel-guardian.test.ts +512 -85
- package/src/__tests__/channel-readiness-slack-remote.test.ts +3 -151
- package/src/__tests__/channel-retry-sweep.test.ts +2 -344
- package/src/__tests__/channel-setup-panel-ack.test.ts +9 -12
- package/src/__tests__/chat-reveal-guard-priming.test.ts +28 -28
- package/src/__tests__/compaction-events.test.ts +8 -8
- package/src/__tests__/config-loader-backfill.test.ts +5 -4
- package/src/__tests__/config-loader-platform-defaults.test.ts +28 -54
- package/src/__tests__/config-model-image-provider.test.ts +0 -20
- package/src/__tests__/config-schema.test.ts +1 -12
- package/src/__tests__/config-set-platform-guard.test.ts +12 -11
- package/src/__tests__/config-sounds-sync.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +3 -3
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +12 -12
- package/src/__tests__/conversation-agent-loop.test.ts +29 -29
- package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +4 -4
- package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +81 -81
- package/src/__tests__/conversation-runtime-assembly.test.ts +0 -27
- package/src/__tests__/conversation-slash-queue.test.ts +11 -11
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
- package/src/__tests__/conversation-speed-override.test.ts +2 -2
- package/src/__tests__/conversation-starter-routes.test.ts +2 -2
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +16 -18
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
- package/src/__tests__/conversation-surfaces-app-open.test.ts +4 -7
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
- package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
- package/src/__tests__/conversation-surfaces-state-update.test.ts +6 -9
- package/src/__tests__/conversation-surfaces-table-action.test.ts +3 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +49 -49
- package/src/__tests__/conversation-sync-tags.test.ts +5 -5
- package/src/__tests__/conversation-usage.test.ts +0 -27
- package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
- package/src/__tests__/credential-security-invariants.test.ts +0 -2
- package/src/__tests__/daemon-assistant-events.test.ts +15 -15
- package/src/__tests__/emit-event-signal.test.ts +6 -6
- package/src/__tests__/events-tail-route.test.ts +4 -6
- package/src/__tests__/guardian-card-withdrawal.test.ts +0 -57
- package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
- package/src/__tests__/host-browser-proxy.test.ts +1 -1
- package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
- package/src/__tests__/image-credentials.test.ts +8 -65
- package/src/__tests__/introduction-card-resolver.test.ts +4 -55
- package/src/__tests__/list-messages-page-latest.test.ts +2 -2
- package/src/__tests__/log-redact.test.ts +0 -18
- package/src/__tests__/managed-profile-guard.test.ts +0 -27
- package/src/__tests__/media-generate-image.test.ts +11 -62
- package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +137 -87
- package/src/__tests__/notification-deep-link.test.ts +12 -12
- package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
- package/src/__tests__/openai-responses-prompt-cache.test.ts +7 -27
- package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
- package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
- package/src/__tests__/playbook-execution.test.ts +2 -2
- package/src/__tests__/playbook-tools.test.ts +2 -2
- package/src/__tests__/plugin-event-hub-facade.test.ts +15 -18
- package/src/__tests__/provider-platform-proxy-integration.test.ts +1 -0
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -7
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +3 -3
- package/src/__tests__/runtime-events-sse-parity.test.ts +10 -10
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +2 -2
- package/src/__tests__/schedule-store.test.ts +3 -3
- package/src/__tests__/secret-patterns.test.ts +27 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
- package/src/__tests__/secret-response-routing.test.ts +3 -3
- package/src/__tests__/secret-scanner.test.ts +0 -36
- package/src/__tests__/send-endpoint-busy.test.ts +7 -7
- package/src/__tests__/slack-inbound-verification.test.ts +20 -45
- package/src/__tests__/slack-share-routes.test.ts +3 -3
- package/src/__tests__/starter-task-flow.test.ts +3 -6
- package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
- package/src/__tests__/subagent-disposal.test.ts +10 -10
- package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
- package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
- package/src/__tests__/subagent-manager-notify.test.ts +10 -10
- package/src/__tests__/subagent-spawn-and-await.test.ts +13 -13
- package/src/__tests__/sync-message-contract.test.ts +3 -3
- package/src/__tests__/task-memory-cleanup.test.ts +11 -13
- package/src/__tests__/tool-preview-lifecycle.test.ts +28 -28
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
- package/src/__tests__/tool-start-timestamp.test.ts +4 -4
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
- package/src/__tests__/ui-work-result-surface.test.ts +3 -3
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
- package/src/__tests__/voice-session-bridge.test.ts +44 -44
- package/src/acp/__tests__/client-handler.test.ts +3 -3
- package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
- package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
- package/src/acp/client-handler.ts +3 -3
- package/src/acp/session-manager.ts +8 -8
- package/src/api/events/subagent-event.ts +2 -2
- package/src/api/index.ts +0 -30
- package/src/approvals/guardian-card-withdrawal.ts +8 -53
- package/src/approvals/guardian-decision-primitive.ts +1 -24
- package/src/approvals/guardian-request-resolvers.ts +6 -38
- package/src/calls/call-controller.ts +27 -27
- package/src/calls/call-setup-flow.ts +5 -22
- package/src/calls/voice-session-bridge.ts +7 -7
- package/src/cli/commands/config.ts +8 -23
- package/src/cli/lib/bundled-marketplace.json +0 -12
- package/src/cli.ts +109 -2
- package/src/config/__tests__/default-profile-catalog.test.ts +2 -48
- package/src/config/__tests__/deployment-context-defaults.test.ts +0 -9
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -13
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -3
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -5
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -5
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -5
- package/src/config/call-site-defaults.ts +17 -14
- package/src/config/default-profile-catalog.ts +51 -125
- package/src/config/default-profile-names.ts +0 -27
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/llm-resolver.ts +2 -2
- package/src/config/loader.ts +1 -7
- package/src/config/raw-config-utils.ts +1 -1
- package/src/config/schemas/llm.ts +1 -9
- package/src/config/schemas/services.ts +2 -10
- package/src/contacts/member-status.ts +1 -21
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
- package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
- package/src/daemon/channel-ui-capability.ts +8 -38
- package/src/daemon/conversation-agent-loop-handlers.ts +3 -3
- package/src/daemon/conversation-agent-loop.ts +4 -4
- package/src/daemon/conversation-messaging.ts +14 -25
- package/src/daemon/conversation-notifiers.ts +2 -2
- package/src/daemon/conversation-process.ts +4 -4
- package/src/daemon/conversation-queue-manager.ts +7 -7
- package/src/daemon/conversation-runtime-assembly.ts +0 -11
- package/src/daemon/conversation-surfaces.ts +4 -4
- package/src/daemon/conversation-tool-setup.ts +3 -8
- package/src/daemon/conversation-usage.ts +14 -24
- package/src/daemon/conversation.ts +11 -11
- package/src/daemon/handlers/config-channels.ts +134 -40
- package/src/daemon/handlers/config-model.ts +7 -15
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/lifecycle.ts +0 -8
- package/src/daemon/message-protocol.ts +151 -16
- package/src/daemon/message-types/acp.ts +20 -0
- package/src/daemon/message-types/apps.ts +356 -0
- package/src/daemon/message-types/background-tools.ts +14 -0
- package/src/daemon/message-types/bookmarks.ts +13 -0
- package/src/daemon/message-types/computer-use.ts +12 -0
- package/src/daemon/message-types/contacts.ts +13 -0
- package/src/daemon/message-types/conversations.ts +345 -9
- package/src/daemon/message-types/document-comments.ts +14 -0
- package/src/daemon/message-types/documents.ts +13 -0
- package/src/daemon/message-types/home.ts +15 -0
- package/src/daemon/message-types/host-app-control.ts +9 -0
- package/src/daemon/message-types/host-bash.ts +12 -0
- package/src/daemon/message-types/host-browser.ts +7 -0
- package/src/daemon/message-types/host-cu.ts +10 -0
- package/src/daemon/message-types/host-file.ts +12 -0
- package/src/daemon/message-types/host-transfer.ts +12 -0
- package/src/daemon/message-types/host-ui-snapshot.ts +7 -0
- package/src/daemon/message-types/integrations.ts +249 -0
- package/src/daemon/message-types/memory.ts +10 -0
- package/src/daemon/message-types/messages.ts +48 -0
- package/src/daemon/message-types/notifications.ts +7 -0
- package/src/daemon/message-types/schedules.ts +14 -0
- package/src/daemon/message-types/settings.ts +17 -0
- package/src/daemon/message-types/skills.ts +5 -0
- package/src/daemon/message-types/subagents.ts +63 -0
- package/src/daemon/message-types/surfaces.ts +82 -34
- package/src/daemon/message-types/sync.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +14 -0
- package/src/daemon/message-types/workflows.ts +25 -0
- package/src/daemon/message-types/workspace.ts +137 -0
- package/src/daemon/process-message.ts +5 -5
- package/src/daemon/tool-setup-types.ts +0 -12
- package/src/daemon/tool-side-effects.ts +10 -10
- package/src/daemon/wake-conversation-ops.ts +4 -4
- package/src/home/conversation-starter-checkpoints.ts +2 -2
- package/src/home/job-handlers/conversation-starters.ts +11 -15
- package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
- package/src/ipc/routes/events-ipc-routes.ts +3 -3
- package/src/mcp/mcp-oauth-provider.ts +1 -59
- package/src/media/app-icon-generator.ts +8 -15
- package/src/media/avatar-router.ts +5 -9
- package/src/media/image-credentials.ts +10 -42
- package/src/media/image-service.ts +13 -1
- package/src/media/types.ts +3 -26
- package/src/messaging/providers/slack/__tests__/auth.test.ts +86 -1
- package/src/messaging/providers/slack/auth.ts +54 -18
- package/src/messaging/providers/slack/withdraw.test.ts +0 -71
- package/src/messaging/providers/slack/withdraw.ts +5 -53
- package/src/monitoring/recovery/run-recovery.ts +0 -2
- package/src/notifications/adapters/macos.ts +3 -3
- package/src/notifications/adapters/slack.ts +0 -6
- package/src/oauth/AGENTS.md +1 -1
- package/src/permissions/confirmation-guardian-request.test.ts +2 -2
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +5 -5
- package/src/permissions/question-prompter.test.ts +8 -8
- package/src/permissions/secret-prompter.ts +2 -2
- package/src/persistence/conversation-crud.ts +1 -4
- package/src/persistence/conversation-title-service.ts +0 -25
- package/src/persistence/delivery-crud.ts +3 -27
- package/src/persistence/delivery-status.ts +2 -60
- package/src/persistence/embeddings/graph-node-orphan-sweep.ts +3 -9
- package/src/persistence/migrations/340-sweep-orphaned-graph-node-vectors.test.ts +0 -16
- package/src/persistence/migrations/341-sweep-cacheless-graph-node-vectors.test.ts +8 -5
- package/src/persistence/raw-query.ts +0 -14
- package/src/persistence/schema/conversations.ts +1 -2
- package/src/persistence/steps.ts +0 -30
- package/src/playbooks/playbook-compiler.ts +2 -5
- package/src/plugin-api/conversation-turn.ts +4 -4
- package/src/plugin-api/event-hub-facade.ts +4 -6
- package/src/plugin-api/index.ts +4 -17
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -8
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +0 -154
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +0 -22
- package/src/plugins/defaults/memory/graph/bootstrap.ts +3 -6
- package/src/plugins/defaults/memory/graph/capability-seed.ts +5 -9
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -11
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +28 -28
- package/src/plugins/defaults/memory/graph/decay.ts +2 -3
- package/src/plugins/defaults/memory/graph/graph-search.ts +2 -3
- package/src/plugins/defaults/memory/graph/retriever.test.ts +11 -7
- package/src/plugins/defaults/memory/graph/store.test.ts +6 -4
- package/src/plugins/defaults/memory/graph/store.ts +22 -43
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +0 -35
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +0 -29
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +17 -24
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +4 -38
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +10 -44
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +25 -94
- package/src/plugins/defaults/memory/v2/backfill-jobs.ts +2 -12
- package/src/plugins/defaults/memory/v2/migration.ts +5 -2
- package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +12 -104
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +12 -104
- package/src/plugins/types.ts +2 -2
- package/src/prompts/templates/system-sections.ts +0 -2
- package/src/providers/__tests__/registry-native-web-search.test.ts +1 -0
- package/src/providers/anthropic/client.ts +9 -11
- package/src/providers/inference/connections.ts +14 -30
- package/src/providers/model-catalog.ts +0 -51
- package/src/providers/openai/responses-provider.ts +4 -13
- package/src/providers/registry.ts +1 -0
- package/src/runtime/AGENTS.md +0 -8
- package/src/runtime/access-request-helper.ts +58 -71
- package/src/runtime/agent-wake.ts +31 -9
- package/src/runtime/assistant-event-hub.ts +18 -18
- package/src/runtime/assistant-event.ts +11 -23
- package/src/runtime/assistant-stream-state.ts +4 -4
- package/src/runtime/channel-approval-types.ts +0 -22
- package/src/runtime/channel-approvals.ts +25 -0
- package/src/runtime/channel-readiness-service.ts +7 -105
- package/src/runtime/channel-retry-sweep.ts +22 -200
- package/src/runtime/guardian-action-service.ts +1 -14
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/introduction-policy.test.ts +0 -8
- package/src/runtime/introduction-policy.ts +2 -14
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -28
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -160
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +0 -29
- package/src/runtime/routes/__tests__/user-routes-cli.test.ts +0 -7
- package/src/runtime/routes/acp-routes.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +11 -11
- package/src/runtime/routes/browser-tabs-routes.ts +1 -2
- package/src/runtime/routes/canned-message-complete.ts +2 -2
- package/src/runtime/routes/conversation-query-routes.ts +24 -57
- package/src/runtime/routes/conversation-routes.ts +2 -8
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/defer-routes.ts +4 -7
- package/src/runtime/routes/events-routes.ts +1 -2
- package/src/runtime/routes/global-search-routes.ts +2 -8
- package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
- package/src/runtime/routes/image-generation-routes.ts +9 -12
- package/src/runtime/routes/inbound-message-handler.ts +64 -187
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +52 -60
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +40 -25
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +0 -158
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +30 -95
- package/src/runtime/routes/inference-provider-connection-routes.ts +6 -101
- package/src/runtime/routes/integrations/slack/__tests__/token-routing.test.ts +85 -38
- package/src/runtime/routes/integrations/slack/channels.ts +13 -9
- package/src/runtime/routes/integrations/slack/share.ts +21 -12
- package/src/runtime/routes/mcp-auth-routes.ts +44 -42
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
- package/src/runtime/routes/sequence-routes.ts +6 -7
- package/src/runtime/routes/suggest-trust-rule-routes.ts +19 -6
- package/src/runtime/routes/surface-action-routes.ts +0 -10
- package/src/runtime/routes/ui-request-routes.ts +1 -2
- package/src/runtime/routes/user-routes-cli.ts +1 -2
- package/src/runtime/routes/watcher-routes.ts +6 -9
- package/src/runtime/routes/workspace-routes.test.ts +2 -2
- package/src/runtime/slack-reply-session.test.ts +12 -12
- package/src/runtime/slack-reply-session.ts +17 -17
- package/src/runtime/sync/sync-publisher.test.ts +5 -7
- package/src/security/AGENTS.md +1 -1
- package/src/security/credential-key.ts +0 -17
- package/src/security/secret-ingress.ts +105 -14
- package/src/security/secret-patterns.ts +139 -8
- package/src/security/secret-scanner.ts +3 -8
- package/src/signals/emit-event.ts +3 -3
- package/src/signals/event-stream.ts +5 -5
- package/src/subagent/manager.ts +15 -15
- package/src/tools/acp/context.ts +5 -5
- package/src/tools/ask-question/ask-question-tool.test.ts +1 -87
- package/src/tools/ask-question/ask-question-tool.ts +0 -58
- package/src/tools/browser/browser-screencast.ts +6 -6
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/tool-types.ts +0 -8
- package/src/tools/types.ts +0 -9
- package/src/util/log-redact.ts +3 -7
- package/src/workflows/leaf-runner.ts +5 -5
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +0 -449
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +0 -468
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +0 -449
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +0 -468
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +0 -449
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +0 -468
- package/src/__tests__/slack-required-scopes-mirror.test.ts +0 -81
- package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +0 -284
- package/src/api/events/app-files-changed.ts +0 -20
- package/src/api/events/oauth-connect-result.ts +0 -26
- package/src/api/events/platform-disconnected.ts +0 -21
- package/src/api/events/show-platform-login.ts +0 -20
- package/src/api/events/ui-surface-undo-result.ts +0 -27
- package/src/daemon/__tests__/channel-ui-capability.test.ts +0 -26
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +0 -75
- package/src/monitoring/recovery/__tests__/orphaned-channel-events.test.ts +0 -144
- package/src/monitoring/recovery/orphaned-channel-events.ts +0 -72
- package/src/persistence/migrations/349-move-memory-graph-tables-to-memory-db.ts +0 -227
- package/src/persistence/migrations/350-conversations-total-input-tokens-nullable.ts +0 -77
- package/src/persistence/migrations/__tests__/350-conversations-total-input-tokens-nullable.test.ts +0 -75
- package/src/plugin-api/__tests__/publish-event.test.ts +0 -54
- package/src/plugin-api/publish-event.ts +0 -39
- package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +0 -87
- package/src/providers/inference/__tests__/credential-slot-repair.test.ts +0 -138
- package/src/providers/inference/credential-slot-repair.ts +0 -110
- package/src/runtime/routes/__tests__/browser-tabs-routes.test.ts +0 -35
- package/src/runtime/routes/__tests__/defer-routes.test.ts +0 -39
- package/src/runtime/routes/__tests__/events-routes.test.ts +0 -40
- package/src/runtime/routes/__tests__/mcp-auth-routes.test.ts +0 -69
- package/src/runtime/routes/__tests__/sequence-routes.test.ts +0 -56
- package/src/runtime/routes/__tests__/ui-request-routes.test.ts +0 -37
- package/src/runtime/routes/__tests__/watcher-routes.test.ts +0 -42
- package/src/runtime/routes/inbound-stages/channel-turn-admission.test.ts +0 -141
- package/src/runtime/routes/inbound-stages/channel-turn-admission.ts +0 -111
- package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +0 -53
- package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +0 -64
- package/src/runtime/routes/parse-body.ts +0 -31
- package/src/util/single-flight.test.ts +0 -88
- package/src/util/single-flight.ts +0 -57
- package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +0 -128
package/README.md
CHANGED
|
@@ -145,7 +145,7 @@ All approval prompt delivery paths use a **fail-closed** policy -- if the prompt
|
|
|
145
145
|
|
|
146
146
|
### Plain-Text Fallback for Non-Rich Channels
|
|
147
147
|
|
|
148
|
-
Channels that do not support rich inline approval UI (e.g., inline keyboards) receive plain-text instructions embedded in the message body. The `
|
|
148
|
+
Channels that do not support rich inline approval UI (e.g., inline keyboards) receive plain-text instructions embedded in the message body. The `channelSupportsRichApprovalUI()` check determines whether to send the structured `promptText` (for rich channels like Telegram) or the `plainTextFallback` string (for all other channels). The fallback text includes instructions so the user can respond via text; the conversational approval engine then classifies the free-text response.
|
|
149
149
|
|
|
150
150
|
### Key modules
|
|
151
151
|
|
|
@@ -39,7 +39,7 @@ Design doc defining how unknown users gain access to a Vellum assistant via chan
|
|
|
39
39
|
|
|
40
40
|
This ensures unknown inbound access attempts always trigger guardian notification, even when the requester's source channel has no guardian binding.
|
|
41
41
|
|
|
42
|
-
4. **Guardian decides.** All decisions route through the guardian decision primitive (`applyGuardianDecision`, `approvals/guardian-decision-primitive.ts`) and commit via the gateway's `guardian_requests_decide` IPC op: the status CAS and the decision's ACL outcome execute in ONE gateway transaction, so an `approved` request can never exist without its ACL write. The introduction card supports four outcomes: **approve** (start the verification handshake), **trust** (activate directly, no code — used for workspace-vouched identities), **
|
|
42
|
+
4. **Guardian decides.** All decisions route through the guardian decision primitive (`applyGuardianDecision`, `approvals/guardian-decision-primitive.ts`) and commit via the gateway's `guardian_requests_decide` IPC op: the status CAS and the decision's ACL outcome execute in ONE gateway transaction, so an `approved` request can never exist without its ACL write. The introduction card supports four outcomes: **approve** (start the verification handshake), **trust** (activate directly, no code — used for workspace-vouched identities), **deny** (persist a terminal denial), and **block**.
|
|
43
43
|
5. **On approval the gateway mints a verification session.** The decide op carries a `mint_outbound_session` outcome; inside the decide transaction the gateway (`gateway/src/verification/session-service.ts`) generates a 6-digit code, persists only its SHA-256 hash in `channel_verification_sessions` (identity-bound to the requester, `verificationPurpose: 'trusted_contact'`), and returns the raw secret to the daemon in the decide response for delivery.
|
|
44
44
|
6. **The code is delivered.** The daemon delivers the code to the guardian's verified channel (ephemeral + DM on Slack shared channels so other members never see it). On Slack the code is also DM'd straight to the requester; on other channels the guardian relays it out-of-band (in person, text message, phone call). That out-of-band transfer is the trust anchor: it proves the requester has a real-world relationship with the guardian.
|
|
45
45
|
7. **Requester enters the code** back to the assistant on the same channel. The **gateway** intercepts bare verification codes at ingress (`gateway/src/verification/text-verification.ts`) whenever an interceptable session exists for that channel — the daemon never sees verification code messages.
|
|
@@ -52,14 +52,14 @@ Design doc defining how unknown users gain access to a Vellum assistant via chan
|
|
|
52
52
|
requested -> pending_guardian -> verification_pending -> active | denied | expired
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
| State | Description | Store representation
|
|
56
|
-
| ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
57
|
-
| `requested` | Unknown user messaged the assistant and was denied. The system records the access attempt. | No member record exists. The inbound is logged in `channel_inbound_events` (assistant DB). A notification signal is emitted via `emitNotificationSignal()`.
|
|
58
|
-
| `pending_guardian` | The guardian has been notified and a decision is pending. | A `guardian_requests` record (gateway DB) with `status: 'pending'`, `kind: 'access_request'`.
|
|
59
|
-
| `verification_pending` | The guardian approved. A verification session is active with a 6-digit code waiting for the requester to enter. | Gateway `channel_verification_sessions` record with `status: 'awaiting_response'`, identity-bound to the requester. The guardian request is `status: 'approved'`.
|
|
60
|
-
| `active` | The requester entered the correct code (or the guardian chose direct trust). They are now a trusted contact. | Gateway `contact_channels` record with `status: 'active'`, `policy: 'allow'`; identity mirrored to the assistant DB. The verification session is `status: 'consumed'`.
|
|
61
|
-
| `denied` | The guardian
|
|
62
|
-
| `expired` | The guardian never responded (approval TTL elapsed) or the requester never entered the code (session TTL elapsed). | Guardian request: `status: 'expired'` (CAS-expired by the gateway via the daemon's expiry sweep). Verification session: expires naturally when `expiresAt < Date.now()`.
|
|
55
|
+
| State | Description | Store representation |
|
|
56
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
57
|
+
| `requested` | Unknown user messaged the assistant and was denied. The system records the access attempt. | No member record exists. The inbound is logged in `channel_inbound_events` (assistant DB). A notification signal is emitted via `emitNotificationSignal()`. |
|
|
58
|
+
| `pending_guardian` | The guardian has been notified and a decision is pending. | A `guardian_requests` record (gateway DB) with `status: 'pending'`, `kind: 'access_request'`. |
|
|
59
|
+
| `verification_pending` | The guardian approved. A verification session is active with a 6-digit code waiting for the requester to enter. | Gateway `channel_verification_sessions` record with `status: 'awaiting_response'`, identity-bound to the requester. The guardian request is `status: 'approved'`. |
|
|
60
|
+
| `active` | The requester entered the correct code (or the guardian chose direct trust). They are now a trusted contact. | Gateway `contact_channels` record with `status: 'active'`, `policy: 'allow'`; identity mirrored to the assistant DB. The verification session is `status: 'consumed'`. |
|
|
61
|
+
| `denied` | The guardian explicitly denied the request. | The guardian request has `status: 'denied'`. The sender is persisted as an unverified contact and later inbound is suppressed (terminal-deny). |
|
|
62
|
+
| `expired` | The guardian never responded (approval TTL elapsed) or the requester never entered the code (session TTL elapsed). | Guardian request: `status: 'expired'` (CAS-expired by the gateway via the daemon's expiry sweep). Verification session: expires naturally when `expiresAt < Date.now()`. |
|
|
63
63
|
|
|
64
64
|
## Identity Binding Rules
|
|
65
65
|
|
|
@@ -112,16 +112,7 @@ Identity binding ensures the verification code can only be consumed by the inten
|
|
|
112
112
|
| -------------------------------------------------- | ------------------- | ------------------------------------------------------------- |
|
|
113
113
|
| gateway `guardian-request-service.ts` (gateway DB) | `guardian_requests` | Updated to `status: 'denied'`, `decidedByExternalUserId` set. |
|
|
114
114
|
|
|
115
|
-
No trusted-contact activation happens. The
|
|
116
|
-
|
|
117
|
-
The two outcomes differ on re-contact. Suppression of re-prompting keys off the **durable contact status**, not this `denied` request status:
|
|
118
|
-
|
|
119
|
-
- `leave_unverified` → `unverified` contact: a neutral park, **not** kept out. If the contact later does something that needs trust — e.g. DMs on a `trusted_contacts` channel — the deny-path flow **re-fires** (self-verify challenge + a fresh guardian card), so the guardian decides afresh. The guardian's way to stop the prompts is to `block`.
|
|
120
|
-
- `block` → `revoked` contact: a durable keep-out. Re-contact is suppressed (no challenge, no guardian notification) on every floor.
|
|
121
|
-
|
|
122
|
-
The resolved approval card mirrors this distinction on every surface (in-app, Slack): a `leave_unverified` park reads as a neutral **"Left unverified"**, while `block` reads as **"Denied"**. Both share the `denied` request status, so the card presentation is keyed off the decided action, not the status (see `PARK_ACTION_SET` / `isParkAction` in `runtime/channel-approval-types.ts`).
|
|
123
|
-
|
|
124
|
-
Separately, the admitted-mode introduction **nudge** (for a contact who cleared the floor unclassified) is quieted once the guardian has decided the contact, so a classified contact is not re-nudged across conversations. That is distinct from the deny-path re-fire above.
|
|
115
|
+
No trusted-contact activation happens. The sender is persisted as an unverified contact, and the terminal-deny check suppresses re-prompting the guardian for the same sender.
|
|
125
116
|
|
|
126
117
|
### Stage: `expired`
|
|
127
118
|
|
|
@@ -200,15 +191,10 @@ sequenceDiagram
|
|
|
200
191
|
GW->>A: Forward with allow verdict
|
|
201
192
|
A->>A: Process message normally
|
|
202
193
|
|
|
203
|
-
else Guardian
|
|
204
|
-
G->>A:
|
|
205
|
-
A->>A: Resolver
|
|
206
|
-
A-->>U: (No notification — user only
|
|
207
|
-
|
|
208
|
-
else Guardian blocks
|
|
209
|
-
G->>A: Block
|
|
210
|
-
A->>A: Resolver revokes the channel (durable keep-out —<br/>re-contact suppressed)
|
|
211
|
-
A-->>U: "Your access request was declined."
|
|
194
|
+
else Guardian denies
|
|
195
|
+
G->>A: Deny (inline button / app / plain text)
|
|
196
|
+
A->>A: Resolver persists denial (terminal-deny)
|
|
197
|
+
A-->>U: (No notification — user only knows<br/>they were denied if they message again)
|
|
212
198
|
|
|
213
199
|
else Guardian never responds
|
|
214
200
|
Note over A: runGuardianExpirySweep()<br/>runs every 60 seconds
|
|
@@ -255,7 +241,7 @@ sequenceDiagram
|
|
|
255
241
|
|
|
256
242
|
- If the unknown user messages the assistant multiple times before the guardian responds, each message hits the ACL denial path independently.
|
|
257
243
|
- `notifyGuardianOfAccessRequest()` dedupes on the existing pending guardian request for the same (assistant, channel, requester), and the notification pipeline's `dedupeKey` prevents duplicate notification events.
|
|
258
|
-
- A
|
|
244
|
+
- A prior terminal deny suppresses re-prompting entirely, and an approval whose verification window is still open suppresses a fresh request (the sender is told to enter their code instead).
|
|
259
245
|
|
|
260
246
|
### Requester already has a member record in non-active state
|
|
261
247
|
|
|
@@ -109,77 +109,12 @@ export type RemoteWebPairingTokenResponse =
|
|
|
109
109
|
// only) so both Node and browser callers share one implementation.
|
|
110
110
|
|
|
111
111
|
/** Why a public base URL can't be advertised in a pairing challenge. */
|
|
112
|
-
export type PublicBaseUrlRejection =
|
|
113
|
-
| "unparseable"
|
|
114
|
-
| "loopback"
|
|
115
|
-
| "non-https"
|
|
116
|
-
| "service-website";
|
|
112
|
+
export type PublicBaseUrlRejection = "unparseable" | "loopback" | "non-https";
|
|
117
113
|
|
|
118
114
|
export type PublicBaseUrlResult =
|
|
119
115
|
| { ok: true; url: string }
|
|
120
116
|
| { ok: false; reason: PublicBaseUrlRejection };
|
|
121
117
|
|
|
122
|
-
/**
|
|
123
|
-
* Hosts that are a tunnel/ingress vendor's own website, not a user's assistant
|
|
124
|
-
* endpoint. These are the tunnel vendors our docs mention, and their sites are
|
|
125
|
-
* exactly where a lost user grabs a URL from — e.g. a Tailscale admin invite
|
|
126
|
-
* link (`login.tailscale.com/admin/invite/…`), which is https and non-loopback
|
|
127
|
-
* and so clears every other check. Pairing refuses them with a targeted message
|
|
128
|
-
* rather than minting a challenge the scanning device can never reach.
|
|
129
|
-
*/
|
|
130
|
-
export const TUNNEL_PROVIDER_WEBSITE_HOSTS = [
|
|
131
|
-
"login.tailscale.com",
|
|
132
|
-
"tailscale.com",
|
|
133
|
-
"www.tailscale.com",
|
|
134
|
-
"ngrok.com",
|
|
135
|
-
"dashboard.ngrok.com",
|
|
136
|
-
"dash.cloudflare.com",
|
|
137
|
-
"cloudflare.com",
|
|
138
|
-
"www.cloudflare.com",
|
|
139
|
-
] as const;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* A URL whose exact host is a tunnel/ingress vendor's own website (see
|
|
143
|
-
* {@link TUNNEL_PROVIDER_WEBSITE_HOSTS}). Exact-host only: a user's real
|
|
144
|
-
* Tailscale endpoint (`*.ts.net`) or Cloudflare-fronted domain is never a
|
|
145
|
-
* listed host, so a legitimate address is never mistaken for a vendor site.
|
|
146
|
-
*/
|
|
147
|
-
export function isTunnelProviderWebsiteUrl(url: string): boolean {
|
|
148
|
-
let hostname: string;
|
|
149
|
-
try {
|
|
150
|
-
// WHATWG URL lowercases the hostname during parsing.
|
|
151
|
-
hostname = new URL(url).hostname;
|
|
152
|
-
} catch {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
return (TUNNEL_PROVIDER_WEBSITE_HOSTS as readonly string[]).includes(
|
|
156
|
-
hostname,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* The display name of the tunnel/ingress vendor a service-website URL points
|
|
162
|
-
* at (`"Tailscale"` / `"ngrok"` / `"Cloudflare"`), or null when the host is not
|
|
163
|
-
* a known vendor site. Drives the "This is <Name>'s website" pairing guidance.
|
|
164
|
-
*/
|
|
165
|
-
export function tunnelProviderWebsiteName(url: string): string | null {
|
|
166
|
-
let hostname: string;
|
|
167
|
-
try {
|
|
168
|
-
hostname = new URL(url).hostname;
|
|
169
|
-
} catch {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
if (
|
|
173
|
-
!(TUNNEL_PROVIDER_WEBSITE_HOSTS as readonly string[]).includes(hostname)
|
|
174
|
-
) {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
if (hostname.includes("tailscale")) return "Tailscale";
|
|
178
|
-
if (hostname.includes("ngrok")) return "ngrok";
|
|
179
|
-
if (hostname.includes("cloudflare")) return "Cloudflare";
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
118
|
/**
|
|
184
119
|
* A loopback URL — `localhost`, `[::1]`, or `127.x.x.x`. A pairing link that
|
|
185
120
|
* encodes a loopback address is unreachable from the scanning device.
|
|
@@ -232,9 +167,6 @@ export function resolvePublicBaseUrl(raw: string): PublicBaseUrlResult {
|
|
|
232
167
|
if (isLoopbackPublicUrl(normalized)) {
|
|
233
168
|
return { ok: false, reason: "loopback" };
|
|
234
169
|
}
|
|
235
|
-
if (isTunnelProviderWebsiteUrl(normalized)) {
|
|
236
|
-
return { ok: false, reason: "service-website" };
|
|
237
|
-
}
|
|
238
170
|
if (new URL(normalized).protocol !== "https:") {
|
|
239
171
|
return { ok: false, reason: "non-https" };
|
|
240
172
|
}
|
|
@@ -109,77 +109,12 @@ export type RemoteWebPairingTokenResponse =
|
|
|
109
109
|
// only) so both Node and browser callers share one implementation.
|
|
110
110
|
|
|
111
111
|
/** Why a public base URL can't be advertised in a pairing challenge. */
|
|
112
|
-
export type PublicBaseUrlRejection =
|
|
113
|
-
| "unparseable"
|
|
114
|
-
| "loopback"
|
|
115
|
-
| "non-https"
|
|
116
|
-
| "service-website";
|
|
112
|
+
export type PublicBaseUrlRejection = "unparseable" | "loopback" | "non-https";
|
|
117
113
|
|
|
118
114
|
export type PublicBaseUrlResult =
|
|
119
115
|
| { ok: true; url: string }
|
|
120
116
|
| { ok: false; reason: PublicBaseUrlRejection };
|
|
121
117
|
|
|
122
|
-
/**
|
|
123
|
-
* Hosts that are a tunnel/ingress vendor's own website, not a user's assistant
|
|
124
|
-
* endpoint. These are the tunnel vendors our docs mention, and their sites are
|
|
125
|
-
* exactly where a lost user grabs a URL from — e.g. a Tailscale admin invite
|
|
126
|
-
* link (`login.tailscale.com/admin/invite/…`), which is https and non-loopback
|
|
127
|
-
* and so clears every other check. Pairing refuses them with a targeted message
|
|
128
|
-
* rather than minting a challenge the scanning device can never reach.
|
|
129
|
-
*/
|
|
130
|
-
export const TUNNEL_PROVIDER_WEBSITE_HOSTS = [
|
|
131
|
-
"login.tailscale.com",
|
|
132
|
-
"tailscale.com",
|
|
133
|
-
"www.tailscale.com",
|
|
134
|
-
"ngrok.com",
|
|
135
|
-
"dashboard.ngrok.com",
|
|
136
|
-
"dash.cloudflare.com",
|
|
137
|
-
"cloudflare.com",
|
|
138
|
-
"www.cloudflare.com",
|
|
139
|
-
] as const;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* A URL whose exact host is a tunnel/ingress vendor's own website (see
|
|
143
|
-
* {@link TUNNEL_PROVIDER_WEBSITE_HOSTS}). Exact-host only: a user's real
|
|
144
|
-
* Tailscale endpoint (`*.ts.net`) or Cloudflare-fronted domain is never a
|
|
145
|
-
* listed host, so a legitimate address is never mistaken for a vendor site.
|
|
146
|
-
*/
|
|
147
|
-
export function isTunnelProviderWebsiteUrl(url: string): boolean {
|
|
148
|
-
let hostname: string;
|
|
149
|
-
try {
|
|
150
|
-
// WHATWG URL lowercases the hostname during parsing.
|
|
151
|
-
hostname = new URL(url).hostname;
|
|
152
|
-
} catch {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
return (TUNNEL_PROVIDER_WEBSITE_HOSTS as readonly string[]).includes(
|
|
156
|
-
hostname,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* The display name of the tunnel/ingress vendor a service-website URL points
|
|
162
|
-
* at (`"Tailscale"` / `"ngrok"` / `"Cloudflare"`), or null when the host is not
|
|
163
|
-
* a known vendor site. Drives the "This is <Name>'s website" pairing guidance.
|
|
164
|
-
*/
|
|
165
|
-
export function tunnelProviderWebsiteName(url: string): string | null {
|
|
166
|
-
let hostname: string;
|
|
167
|
-
try {
|
|
168
|
-
hostname = new URL(url).hostname;
|
|
169
|
-
} catch {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
if (
|
|
173
|
-
!(TUNNEL_PROVIDER_WEBSITE_HOSTS as readonly string[]).includes(hostname)
|
|
174
|
-
) {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
if (hostname.includes("tailscale")) return "Tailscale";
|
|
178
|
-
if (hostname.includes("ngrok")) return "ngrok";
|
|
179
|
-
if (hostname.includes("cloudflare")) return "Cloudflare";
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
118
|
/**
|
|
184
119
|
* A loopback URL — `localhost`, `[::1]`, or `127.x.x.x`. A pairing link that
|
|
185
120
|
* encodes a loopback address is unreachable from the scanning device.
|
|
@@ -232,9 +167,6 @@ export function resolvePublicBaseUrl(raw: string): PublicBaseUrlResult {
|
|
|
232
167
|
if (isLoopbackPublicUrl(normalized)) {
|
|
233
168
|
return { ok: false, reason: "loopback" };
|
|
234
169
|
}
|
|
235
|
-
if (isTunnelProviderWebsiteUrl(normalized)) {
|
|
236
|
-
return { ok: false, reason: "service-website" };
|
|
237
|
-
}
|
|
238
170
|
if (new URL(normalized).protocol !== "https:") {
|
|
239
171
|
return { ok: false, reason: "non-https" };
|
|
240
172
|
}
|
|
@@ -109,77 +109,12 @@ export type RemoteWebPairingTokenResponse =
|
|
|
109
109
|
// only) so both Node and browser callers share one implementation.
|
|
110
110
|
|
|
111
111
|
/** Why a public base URL can't be advertised in a pairing challenge. */
|
|
112
|
-
export type PublicBaseUrlRejection =
|
|
113
|
-
| "unparseable"
|
|
114
|
-
| "loopback"
|
|
115
|
-
| "non-https"
|
|
116
|
-
| "service-website";
|
|
112
|
+
export type PublicBaseUrlRejection = "unparseable" | "loopback" | "non-https";
|
|
117
113
|
|
|
118
114
|
export type PublicBaseUrlResult =
|
|
119
115
|
| { ok: true; url: string }
|
|
120
116
|
| { ok: false; reason: PublicBaseUrlRejection };
|
|
121
117
|
|
|
122
|
-
/**
|
|
123
|
-
* Hosts that are a tunnel/ingress vendor's own website, not a user's assistant
|
|
124
|
-
* endpoint. These are the tunnel vendors our docs mention, and their sites are
|
|
125
|
-
* exactly where a lost user grabs a URL from — e.g. a Tailscale admin invite
|
|
126
|
-
* link (`login.tailscale.com/admin/invite/…`), which is https and non-loopback
|
|
127
|
-
* and so clears every other check. Pairing refuses them with a targeted message
|
|
128
|
-
* rather than minting a challenge the scanning device can never reach.
|
|
129
|
-
*/
|
|
130
|
-
export const TUNNEL_PROVIDER_WEBSITE_HOSTS = [
|
|
131
|
-
"login.tailscale.com",
|
|
132
|
-
"tailscale.com",
|
|
133
|
-
"www.tailscale.com",
|
|
134
|
-
"ngrok.com",
|
|
135
|
-
"dashboard.ngrok.com",
|
|
136
|
-
"dash.cloudflare.com",
|
|
137
|
-
"cloudflare.com",
|
|
138
|
-
"www.cloudflare.com",
|
|
139
|
-
] as const;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* A URL whose exact host is a tunnel/ingress vendor's own website (see
|
|
143
|
-
* {@link TUNNEL_PROVIDER_WEBSITE_HOSTS}). Exact-host only: a user's real
|
|
144
|
-
* Tailscale endpoint (`*.ts.net`) or Cloudflare-fronted domain is never a
|
|
145
|
-
* listed host, so a legitimate address is never mistaken for a vendor site.
|
|
146
|
-
*/
|
|
147
|
-
export function isTunnelProviderWebsiteUrl(url: string): boolean {
|
|
148
|
-
let hostname: string;
|
|
149
|
-
try {
|
|
150
|
-
// WHATWG URL lowercases the hostname during parsing.
|
|
151
|
-
hostname = new URL(url).hostname;
|
|
152
|
-
} catch {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
return (TUNNEL_PROVIDER_WEBSITE_HOSTS as readonly string[]).includes(
|
|
156
|
-
hostname,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* The display name of the tunnel/ingress vendor a service-website URL points
|
|
162
|
-
* at (`"Tailscale"` / `"ngrok"` / `"Cloudflare"`), or null when the host is not
|
|
163
|
-
* a known vendor site. Drives the "This is <Name>'s website" pairing guidance.
|
|
164
|
-
*/
|
|
165
|
-
export function tunnelProviderWebsiteName(url: string): string | null {
|
|
166
|
-
let hostname: string;
|
|
167
|
-
try {
|
|
168
|
-
hostname = new URL(url).hostname;
|
|
169
|
-
} catch {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
if (
|
|
173
|
-
!(TUNNEL_PROVIDER_WEBSITE_HOSTS as readonly string[]).includes(hostname)
|
|
174
|
-
) {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
if (hostname.includes("tailscale")) return "Tailscale";
|
|
178
|
-
if (hostname.includes("ngrok")) return "ngrok";
|
|
179
|
-
if (hostname.includes("cloudflare")) return "Cloudflare";
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
118
|
/**
|
|
184
119
|
* A loopback URL — `localhost`, `[::1]`, or `127.x.x.x`. A pairing link that
|
|
185
120
|
* encodes a loopback address is unreachable from the scanning device.
|
|
@@ -232,9 +167,6 @@ export function resolvePublicBaseUrl(raw: string): PublicBaseUrlResult {
|
|
|
232
167
|
if (isLoopbackPublicUrl(normalized)) {
|
|
233
168
|
return { ok: false, reason: "loopback" };
|
|
234
169
|
}
|
|
235
|
-
if (isTunnelProviderWebsiteUrl(normalized)) {
|
|
236
|
-
return { ok: false, reason: "service-website" };
|
|
237
|
-
}
|
|
238
170
|
if (new URL(normalized).protocol !== "https:") {
|
|
239
171
|
return { ok: false, reason: "non-https" };
|
|
240
172
|
}
|
package/openapi.yaml
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
openapi: 3.1.0
|
|
4
4
|
info:
|
|
5
5
|
title: Vellum Assistant API
|
|
6
|
-
version: 0.10.
|
|
6
|
+
version: 0.10.11
|
|
7
7
|
description: Auto-generated OpenAPI specification for the Vellum Assistant runtime HTTP server.
|
|
8
8
|
servers:
|
|
9
9
|
- url: http://127.0.0.1:7821
|
|
@@ -17480,8 +17480,8 @@ paths:
|
|
|
17480
17480
|
summary: Create a memory by remembering a fact
|
|
17481
17481
|
description:
|
|
17482
17482
|
Append a user-authored fact to the memory buffer via handleRemember. The fact surfaces in the memory graph
|
|
17483
|
-
immediately as a pending node
|
|
17484
|
-
|
|
17483
|
+
immediately as a pending node, and a consolidation run is nudged (deduped, backoff-respecting) so it files into
|
|
17484
|
+
concept pages promptly.
|
|
17485
17485
|
tags:
|
|
17486
17486
|
- memory
|
|
17487
17487
|
requestBody:
|
|
@@ -17507,11 +17507,6 @@ paths:
|
|
|
17507
17507
|
type: string
|
|
17508
17508
|
success:
|
|
17509
17509
|
type: boolean
|
|
17510
|
-
pendingNodeId:
|
|
17511
|
-
description:
|
|
17512
|
-
Graph node id (`buffer:<hash>`) of the pending entry this create appended, for fly-to-node navigation.
|
|
17513
|
-
Absent when the buffer can't be re-read.
|
|
17514
|
-
type: string
|
|
17515
17510
|
required:
|
|
17516
17511
|
- message
|
|
17517
17512
|
- success
|
|
@@ -19356,12 +19351,6 @@ paths:
|
|
|
19356
19351
|
- low
|
|
19357
19352
|
- medium
|
|
19358
19353
|
- high
|
|
19359
|
-
bypassSecretCheck:
|
|
19360
|
-
description:
|
|
19361
|
-
When true, skip the secret-ingress scan for this message only. Set exclusively when the user explicitly
|
|
19362
|
-
confirms a client-side blocked send (the composer's "Send anyway" action); it is per-message and
|
|
19363
|
-
never persisted.
|
|
19364
|
-
type: boolean
|
|
19365
19354
|
hidden:
|
|
19366
19355
|
description:
|
|
19367
19356
|
"When true, persist the user message but suppress it from the UI transcript (it stays in LLM-side history
|
|
@@ -29407,12 +29396,6 @@ paths:
|
|
|
29407
29396
|
description:
|
|
29408
29397
|
Guardian-facing reply from the resolver (e.g. verification code for access-request approvals). Present only
|
|
29409
29398
|
when applied is true and the resolver produced a reply.
|
|
29410
|
-
decidedAction:
|
|
29411
|
-
type: string
|
|
29412
|
-
description:
|
|
29413
|
-
The action to present on the resolved card — the resolved outcome, not necessarily the raw button (an
|
|
29414
|
-
access-request 'reject' resolves to the 'leave_unverified' park). Present only when applied is
|
|
29415
|
-
true; lets a client completing the card optimistically render the correct tone.
|
|
29416
29399
|
required:
|
|
29417
29400
|
- ok
|
|
29418
29401
|
additionalProperties: false
|
|
@@ -32459,10 +32442,8 @@ components:
|
|
|
32459
32442
|
anyOf:
|
|
32460
32443
|
- type: object
|
|
32461
32444
|
properties:
|
|
32462
|
-
|
|
32463
|
-
|
|
32464
|
-
model:
|
|
32465
|
-
type: string
|
|
32445
|
+
mode:
|
|
32446
|
+
$ref: "#/components/schemas/ServiceMode"
|
|
32466
32447
|
additionalProperties: {}
|
|
32467
32448
|
- type: "null"
|
|
32468
32449
|
inference:
|
|
@@ -33273,10 +33254,8 @@ components:
|
|
|
33273
33254
|
image-generation:
|
|
33274
33255
|
type: object
|
|
33275
33256
|
properties:
|
|
33276
|
-
|
|
33277
|
-
|
|
33278
|
-
model:
|
|
33279
|
-
type: string
|
|
33257
|
+
mode:
|
|
33258
|
+
$ref: "#/components/schemas/ServiceMode"
|
|
33280
33259
|
additionalProperties: {}
|
|
33281
33260
|
inference:
|
|
33282
33261
|
type: object
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import { VellumAcpClientHandler } from "../acp/client-handler.js";
|
|
4
4
|
import { AcpSessionManager } from "../acp/session-manager.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
6
6
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
7
7
|
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
@@ -10,8 +10,8 @@ import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
|
|
12
12
|
describe("VellumAcpClientHandler", () => {
|
|
13
|
-
let sent:
|
|
14
|
-
let sendToVellum: (msg:
|
|
13
|
+
let sent: ServerMessage[];
|
|
14
|
+
let sendToVellum: (msg: ServerMessage) => void;
|
|
15
15
|
let handler: VellumAcpClientHandler;
|
|
16
16
|
|
|
17
17
|
beforeEach(() => {
|
|
@@ -11,7 +11,7 @@ import { Minimatch } from "minimatch";
|
|
|
11
11
|
import { CompactionCircuit } from "../agent/compaction-circuit.js";
|
|
12
12
|
import type { AgentEvent } from "../agent/loop.js";
|
|
13
13
|
import type { ConfirmationStateChangedEvent } from "../api/events/confirmation-state-changed.js";
|
|
14
|
-
import type {
|
|
14
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
15
15
|
import type { Message, ProviderResponse } from "../providers/types.js";
|
|
16
16
|
import type { ConfirmationDetails } from "../runtime/pending-interactions.js";
|
|
17
17
|
|
|
@@ -188,7 +188,7 @@ function makeProvider() {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
function makeConversation(
|
|
191
|
-
sendToClient?: (msg:
|
|
191
|
+
sendToClient?: (msg: ServerMessage) => void,
|
|
192
192
|
conversationId = CONV_ID,
|
|
193
193
|
): Conversation {
|
|
194
194
|
return new Conversation(
|
|
@@ -257,7 +257,7 @@ beforeEach(() => {
|
|
|
257
257
|
|
|
258
258
|
describe("approval cascading", () => {
|
|
259
259
|
test("allow (one-time) does NOT cascade", () => {
|
|
260
|
-
const emitted:
|
|
260
|
+
const emitted: ServerMessage[] = [];
|
|
261
261
|
const conversationObj = makeConversation(
|
|
262
262
|
(msg) => emitted.push(msg),
|
|
263
263
|
CONV_ID,
|
|
@@ -291,7 +291,7 @@ describe("approval cascading", () => {
|
|
|
291
291
|
});
|
|
292
292
|
|
|
293
293
|
test("deny (one-time) does NOT cascade", () => {
|
|
294
|
-
const emitted:
|
|
294
|
+
const emitted: ServerMessage[] = [];
|
|
295
295
|
const conversationObj = makeConversation(
|
|
296
296
|
(msg) => emitted.push(msg),
|
|
297
297
|
CONV_ID,
|
|
@@ -325,7 +325,7 @@ describe("approval cascading", () => {
|
|
|
325
325
|
});
|
|
326
326
|
|
|
327
327
|
test("already-resolved request handled gracefully", () => {
|
|
328
|
-
const emitted:
|
|
328
|
+
const emitted: ServerMessage[] = [];
|
|
329
329
|
const conversationObj = makeConversation(
|
|
330
330
|
(msg) => emitted.push(msg),
|
|
331
331
|
CONV_ID,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
8
8
|
|
|
9
9
|
import type { Conversation } from "../daemon/conversation.js";
|
|
10
|
-
import type {
|
|
10
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
11
11
|
import type { SecretPromptResult } from "../permissions/secret-prompt-types.js";
|
|
12
12
|
|
|
13
13
|
mock.module("../config/env.js", () => ({
|
|
@@ -123,7 +123,7 @@ function makeIdleSession(opts?: {
|
|
|
123
123
|
runAgentLoop: async (
|
|
124
124
|
_content: string,
|
|
125
125
|
_messageId: string,
|
|
126
|
-
options?: { onEvent?: (msg:
|
|
126
|
+
options?: { onEvent?: (msg: ServerMessage) => void },
|
|
127
127
|
) => {
|
|
128
128
|
const onEvent = options?.onEvent ?? (() => {});
|
|
129
129
|
onEvent({ type: "assistant_text_delta", text: "Hello!" });
|
|
@@ -186,7 +186,7 @@ function makeConfirmationEmittingSession(opts?: {
|
|
|
186
186
|
runAgentLoop: async (
|
|
187
187
|
_content: string,
|
|
188
188
|
_messageId: string,
|
|
189
|
-
options?: { onEvent?: (msg:
|
|
189
|
+
options?: { onEvent?: (msg: ServerMessage) => void },
|
|
190
190
|
) => {
|
|
191
191
|
const onEvent = options?.onEvent ?? (() => {});
|
|
192
192
|
// Simulate PermissionPrompter.prompt(): self-register in pendingInteractions
|