@vellumai/assistant 0.11.7 → 0.11.8-dev.202609012313.7a1acce
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +11 -11
- package/Dockerfile +1 -0
- package/docs/architecture/security.md +1 -1
- package/docs/error-handling.md +1 -2
- package/docs/guardian-request-flow.md +64 -18
- package/docs/trusted-contact-access.md +13 -12
- package/knip.json +1 -0
- package/node_modules/@vellumai/avatar-catalog/package.json +19 -0
- package/{src/avatar/character-components.ts → node_modules/@vellumai/avatar-catalog/src/catalog.ts} +12 -44
- package/node_modules/@vellumai/avatar-catalog/src/colors.ts +19 -0
- package/node_modules/@vellumai/avatar-catalog/src/index.ts +25 -0
- package/node_modules/@vellumai/avatar-catalog/src/types.ts +47 -0
- package/node_modules/@vellumai/avatar-catalog/tsconfig.json +20 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +7 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/no-response.ts +84 -0
- package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +43 -12
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/test-path-guard.test.ts +89 -0
- package/node_modules/@vellumai/environments/src/test-path-guard.ts +113 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +7 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/no-response.ts +84 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-request-contract.test.ts +8 -36
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +46 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +46 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-request-contract.ts +62 -42
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +53 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +11 -7
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +1 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +7 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/no-response.ts +84 -0
- package/openapi.yaml +510 -9
- package/package.json +3 -1
- package/scripts/sync-llm-catalog.ts +3 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -2
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +16 -0
- package/src/__tests__/agent-loop-compacted-history-transform.test.ts +304 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +3 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +3 -0
- package/src/__tests__/anthropic-provider.test.ts +58 -0
- package/src/__tests__/approval-cascade.test.ts +0 -13
- package/src/__tests__/attachments-store.test.ts +117 -6
- package/src/__tests__/attachments.test.ts +122 -0
- package/src/__tests__/bundled-asset.test.ts +22 -1
- package/src/__tests__/channel-approval.test.ts +14 -7
- package/src/__tests__/channel-approvals.test.ts +3 -3
- package/src/__tests__/channel-availability-routes.test.ts +15 -0
- package/src/__tests__/channel-delivery-store.test.ts +169 -0
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -0
- package/src/__tests__/channel-invite-transport.test.ts +1 -0
- package/src/__tests__/channel-readiness-routes.test.ts +96 -3
- package/src/__tests__/channel-readiness-service.test.ts +19 -4
- package/src/__tests__/channel-readiness-slack-remote.test.ts +3 -3
- package/src/__tests__/channel-reply-delivery.test.ts +126 -2
- package/src/__tests__/channel-retry-sweep.test.ts +168 -0
- package/src/__tests__/compaction-events.test.ts +0 -12
- package/src/__tests__/compactor-call-site-logging.test.ts +7 -1
- package/src/__tests__/compactor-retained-image-validation.test.ts +15 -0
- package/src/__tests__/config-loader-backfill.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/contacts-write.test.ts +141 -3
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -13
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -12
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -13
- package/src/__tests__/conversation-agent-loop.test.ts +95 -13
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -13
- package/src/__tests__/conversation-error.test.ts +15 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +536 -0
- package/src/__tests__/conversation-media-retry.test.ts +33 -2
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +0 -12
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -13
- package/src/__tests__/conversation-queue.test.ts +4 -13
- package/src/__tests__/conversation-retry-route.test.ts +5 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-sight-frames.test.ts +615 -0
- package/src/__tests__/conversation-slash-queue.test.ts +0 -13
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -13
- package/src/__tests__/conversation-speed-override.test.ts +0 -12
- package/src/__tests__/conversation-store-ephemeral.test.ts +0 -12
- package/src/__tests__/conversation-summarize-route.test.ts +5 -0
- package/src/__tests__/conversation-summarize-up-to.test.ts +102 -0
- package/src/__tests__/conversation-wait-for-idle.test.ts +0 -12
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -17
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -17
- package/src/__tests__/credential-health-service.test.ts +45 -0
- package/src/__tests__/credential-record-retire.test.ts +256 -0
- package/src/__tests__/credential-record-write-through.test.ts +8 -4
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +0 -4
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +0 -4
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +0 -8
- package/src/__tests__/delete-propagation.test.ts +421 -3
- package/src/__tests__/email-invite-adapter.test.ts +53 -12
- package/src/__tests__/evict-conversations-for-reload.test.ts +46 -6
- package/src/__tests__/external-binding-chat-name.test.ts +60 -0
- package/src/__tests__/file-ops-service.test.ts +8 -3
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/guardian-action-service-scope.test.ts +118 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +299 -27
- package/src/__tests__/guardian-expiry-notifier.test.ts +117 -13
- package/src/__tests__/guardian-gateway-sim.test.ts +119 -0
- package/src/__tests__/guardian-gateway-sim.ts +51 -38
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +6 -2
- package/src/__tests__/guardian-request-status-sync.test.ts +162 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -5
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +28 -0
- package/src/__tests__/guardian-wait-controller.test.ts +6 -0
- package/src/__tests__/headless-browser-mode.test.ts +27 -0
- package/src/__tests__/helpers/mock-conversation.ts +2 -0
- package/src/__tests__/list-messages-page-latest.test.ts +85 -0
- package/src/__tests__/list-messages-system-card.test.ts +70 -0
- package/src/__tests__/llm-catalog-parity.test.ts +2 -0
- package/src/__tests__/managed-profile-guard.test.ts +3 -3
- package/src/__tests__/media-resolve-image-validation.test.ts +106 -0
- package/src/__tests__/media-stream-server-integration.test.ts +6 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -0
- package/src/__tests__/notification-discord-adapter.test.ts +76 -4
- package/src/__tests__/oauth-commands-routes.test.ts +21 -0
- package/src/__tests__/openai-provider.test.ts +63 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +128 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +63 -1
- package/src/__tests__/persist-unsendable-image.test.ts +19 -0
- package/src/__tests__/plugin-app-serve-routes.test.ts +2 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +1 -0
- package/src/__tests__/pricing.test.ts +13 -0
- package/src/__tests__/process-message-background-slack.test.ts +1 -1
- package/src/__tests__/process-message-display-content.test.ts +1 -1
- package/src/__tests__/processing-flag-persist-failure.test.ts +0 -5
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +0 -17
- package/src/__tests__/provider-meta-persistence.test.ts +67 -0
- package/src/__tests__/qdrant-manager.test.ts +6 -0
- package/src/__tests__/reaction-persistence.test.ts +78 -260
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +67 -0
- package/src/__tests__/server-history-render.test.ts +22 -0
- package/src/__tests__/sight-frame-retention.test.ts +362 -0
- package/src/__tests__/skill-load-tool.test.ts +27 -0
- package/src/__tests__/skills.test.ts +34 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
- package/src/__tests__/subagent-manager-notify.test.ts +2 -0
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-notify-stale-rebuild.test.ts +85 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +4 -4
- package/src/__tests__/terminal-tools.test.ts +9 -9
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +16 -3
- package/src/__tests__/tool-result-spool.test.ts +5 -8
- package/src/__tests__/usage-attribution.test.ts +26 -0
- package/src/acp/__tests__/acp-auth-marker-store.test.ts +191 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +262 -0
- package/src/acp/__tests__/acp-connect-card-state.test.ts +17 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +10 -3
- package/src/acp/acp-auth-marker-store.ts +196 -0
- package/src/acp/acp-claude-oauth.ts +154 -4
- package/src/acp/acp-connect-card-state.ts +49 -8
- package/src/acp/agent-process.ts +1 -0
- package/src/acp/auto-install.ts +1 -0
- package/src/acp/client-handler.ts +1 -0
- package/src/acp/prepare-agent-env.ts +79 -1
- package/src/acp/resolve-agent.ts +12 -0
- package/src/acp/session-manager.test.ts +183 -0
- package/src/acp/session-manager.ts +110 -6
- package/src/acp/types.ts +17 -0
- package/src/agent/attachments.ts +7 -2
- package/src/agent/loop.ts +59 -1
- package/src/api/events/contact-form-closed.ts +32 -0
- package/src/api/events/contact-record-request.ts +63 -0
- package/src/api/events/contact-request.ts +10 -3
- package/src/api/index.ts +20 -0
- package/src/api/responses/conversation-message.ts +20 -0
- package/src/api/responses/home.ts +95 -0
- package/src/approvals/AGENTS.md +2 -2
- package/src/approvals/guardian-card-withdrawal.ts +127 -30
- package/src/approvals/guardian-decision-primitive.ts +9 -0
- package/src/approvals/guardian-expiry-notifier.ts +22 -16
- package/src/approvals/guardian-request-status-sync.ts +98 -0
- package/src/avatar/svg-compositor.ts +1 -1
- package/src/avatar/traits-png-sync.ts +1 -1
- package/src/bundler/app-compiler.ts +1 -0
- package/src/bundler/compiler-tools.ts +1 -0
- package/src/bundler/package-resolver.ts +1 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +183 -3
- package/src/calls/guardian-action-sweep.ts +6 -1
- package/src/calls/voice-session-bridge.ts +46 -1
- package/src/channels/__tests__/gateway-guardian-requests.test.ts +14 -41
- package/src/channels/gateway-guardian-requests.ts +29 -32
- package/src/cli/__tests__/contacts-record-prompt-cli.test.ts +329 -0
- package/src/cli/commands/__tests__/browser.test.ts +65 -1
- package/src/cli/commands/browser.ts +30 -10
- package/src/cli/commands/contacts.help.ts +173 -11
- package/src/cli/commands/contacts.ts +343 -4
- package/src/cli/commands/db/__tests__/status.test.ts +22 -0
- package/src/cli/commands/db/index.help.ts +1 -1
- package/src/cli/commands/db/refresh.ts +1 -0
- package/src/cli/commands/db/status.ts +172 -1
- package/src/cli/commands/oauth/index.help.ts +6 -3
- package/src/cli/commands/oauth/request.test.ts +37 -0
- package/src/cli/commands/oauth/request.ts +7 -6
- package/src/cli/lib/bundled-marketplace.json +1 -1
- package/src/cli/lib/install-from-github.ts +20 -19
- package/src/cli/lib/install-plugin-dependencies.ts +3 -5
- package/src/cli/lib/merge-plugin-tree.ts +1 -0
- package/src/cli/lib/publish-plugin.ts +4 -1
- package/src/config/__tests__/balanced-model-experiment.test.ts +63 -31
- package/src/config/__tests__/default-profile-catalog.test.ts +3 -3
- package/src/config/balanced-model-experiment.ts +15 -9
- package/src/config/bundled-skills/acp/SKILL.md +10 -3
- package/src/config/bundled-skills/contacts/SKILL.md +61 -18
- package/src/config/bundled-skills/schedule/SKILL.md +23 -11
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +3 -1
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/default-profile-catalog.ts +24 -23
- package/src/config/default-profile-names.ts +2 -2
- package/src/config/feature-flag-registry.json +22 -13
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +13 -0
- package/src/config/schemas/live-voice.ts +7 -0
- package/src/config/schemas/sight.ts +45 -0
- package/src/config/skills.ts +2 -1
- package/src/contacts/__tests__/mirror-reconciler.test.ts +352 -0
- package/src/contacts/contact-store.ts +47 -4
- package/src/contacts/contacts-write.ts +5 -2
- package/src/contacts/mirror-reconciler.ts +210 -0
- package/src/contacts/mirror-tombstones.ts +42 -0
- package/src/contacts/notify-contacts-changed.ts +11 -2
- package/src/context/compactor.ts +47 -19
- package/src/context/tool-result-spool.ts +21 -14
- package/src/conversations/message-consolidation.ts +2 -2
- package/src/credential-health/credential-health-service.ts +37 -6
- package/src/daemon/conversation-agent-loop-handlers.ts +19 -2
- package/src/daemon/conversation-agent-loop.ts +100 -1
- package/src/daemon/conversation-error.ts +2 -0
- package/src/daemon/conversation-media-retry.ts +11 -6
- package/src/daemon/conversation-messaging.ts +335 -30
- package/src/daemon/conversation-process.ts +0 -1
- package/src/daemon/conversation-runtime-assembly.ts +67 -0
- package/src/daemon/conversation-sight-frames.ts +187 -0
- package/src/daemon/conversation-store.ts +18 -28
- package/src/daemon/conversation-surfaces.ts +12 -2
- package/src/daemon/conversation-tool-setup.ts +39 -10
- package/src/daemon/conversation.ts +181 -16
- package/src/daemon/daemon-control.ts +6 -17
- package/src/daemon/handlers/config-channels.ts +33 -3
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +10 -11
- package/src/daemon/handlers/shared.ts +9 -0
- package/src/daemon/install-assistant-command.ts +1 -0
- package/src/daemon/lifecycle.ts +10 -13
- package/src/daemon/message-types/sync.ts +4 -0
- package/src/daemon/process-message.ts +89 -33
- package/src/daemon/reaction-history-render.test.ts +162 -0
- package/src/daemon/reaction-history-render.ts +115 -0
- package/src/daemon/reaction-record.test.ts +162 -0
- package/src/daemon/reaction-record.ts +76 -0
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/summarize-boundary.ts +12 -0
- package/src/daemon/video-thumbnail.ts +1 -1
- package/src/email/byo-email-credential.test.ts +39 -0
- package/src/email/byo-email-credential.ts +76 -0
- package/src/email/registered-inbox.test.ts +272 -0
- package/src/email/registered-inbox.ts +169 -0
- package/src/home/feed-types.ts +4 -0
- package/src/home/feed-writer.ts +25 -0
- package/src/live-voice/__tests__/live-voice-attach-frame.test.ts +679 -0
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +8 -5
- package/src/live-voice/__tests__/live-voice-photo.test.ts +637 -1
- package/src/live-voice/__tests__/live-voice-sight-frame-inline.test.ts +787 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +416 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +109 -0
- package/src/live-voice/live-voice-photo.ts +420 -65
- package/src/live-voice/live-voice-session.ts +314 -27
- package/src/live-voice/protocol.ts +166 -11
- package/src/messaging/provider-message-metadata.ts +19 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +113 -1
- package/src/messaging/providers/channel-transport.ts +37 -0
- package/src/messaging/providers/discord/api.ts +4 -4
- package/src/messaging/providers/discord/send.test.ts +177 -2
- package/src/messaging/providers/discord/send.ts +197 -10
- package/src/messaging/providers/discord/transport.ts +10 -0
- package/src/messaging/providers/index.ts +42 -0
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +129 -3
- package/src/messaging/providers/slack/__tests__/auth.test.ts +35 -0
- package/src/messaging/providers/slack/__tests__/message-content.test.ts +152 -0
- package/src/messaging/providers/slack/adapter.ts +112 -27
- package/src/messaging/providers/slack/api.test.ts +10 -0
- package/src/messaging/providers/slack/api.ts +11 -1
- package/src/messaging/providers/slack/approval-source.test.ts +70 -0
- package/src/messaging/providers/slack/approval-source.ts +18 -5
- package/src/messaging/providers/slack/auth.ts +32 -6
- package/src/messaging/providers/slack/client.ts +0 -15
- package/src/messaging/providers/slack/message-content.ts +137 -0
- package/src/messaging/providers/slack/send.test.ts +43 -2
- package/src/messaging/providers/slack/send.ts +18 -5
- package/src/messaging/providers/slack/transport.ts +10 -0
- package/src/messaging/providers/slack/types.ts +21 -2
- package/src/messaging/providers/telegram-bot/adapter.ts +5 -1
- package/src/messaging/providers/telegram-bot/send.test.ts +49 -2
- package/src/messaging/providers/telegram-bot/send.ts +41 -1
- package/src/messaging/providers/telegram-bot/transport.ts +10 -0
- package/src/messaging/providers/telegram-bot/withdraw.ts +13 -5
- package/src/messaging/reaction-envelopes.ts +95 -0
- package/src/monitoring/control.ts +2 -2
- package/src/monitoring/page-cache.ts +5 -1
- package/src/monitoring/recovery/__tests__/stranded-delivery-events.test.ts +208 -0
- package/src/monitoring/recovery/db.ts +35 -0
- package/src/monitoring/recovery/orphaned-channel-events.ts +3 -22
- package/src/monitoring/recovery/run-recovery.ts +6 -2
- package/src/monitoring/recovery/stale-processing.ts +3 -20
- package/src/monitoring/recovery/stranded-delivery-events.ts +68 -0
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +359 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +8 -0
- package/src/notifications/adapters/discord.ts +62 -9
- package/src/notifications/approval-card-data.ts +13 -5
- package/src/notifications/conversation-pairing.ts +31 -4
- package/src/notifications/guardian-delivery-recorder.ts +52 -15
- package/src/notifications/guardian-feed-projection.ts +427 -0
- package/src/notifications/guardian-question-mode.ts +33 -1
- package/src/notifications/home-feed-side-effect.ts +55 -11
- package/src/oauth/byo-connection.test.ts +22 -0
- package/src/oauth/byo-connection.ts +11 -5
- package/src/oauth/connection.ts +3 -2
- package/src/oauth/platform-connection.test.ts +35 -0
- package/src/oauth/platform-connection.ts +18 -13
- package/src/oauth/scope-utils.ts +48 -0
- package/src/oauth/seed-providers.ts +12 -0
- package/src/outbound-proxy/certs.ts +5 -4
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -1
- package/src/permissions/question-guardian-request.test.ts +7 -1
- package/src/persistence/attachments-store.ts +134 -31
- package/src/persistence/conversation-crud.ts +137 -4
- package/src/persistence/conversation-types.ts +109 -0
- package/src/persistence/db-connection.ts +3 -21
- package/src/persistence/delivery-crud.ts +254 -28
- package/src/persistence/delivery-status.ts +21 -2
- package/src/persistence/embeddings/__tests__/embedding-local-lifecycle.test.ts +15 -2
- package/src/persistence/embeddings/embedding-local.ts +7 -112
- package/src/persistence/embeddings/qdrant-manager.ts +4 -1
- package/src/persistence/external-conversation-store.ts +5 -1
- package/src/persistence/llm-request-log-store.ts +1 -1
- package/src/persistence/migrations/370-acp-session-history-auth-error-code.ts +36 -0
- package/src/persistence/migrations/371-acp-session-history-auth-error-credential.ts +40 -0
- package/src/persistence/migrations/372-create-acp-refused-credentials.ts +34 -0
- package/src/persistence/migrations/373-acp-auth-marker-index.ts +27 -0
- package/src/persistence/migrations/374-channel-inbound-message-id-index.ts +26 -0
- package/src/persistence/migrations/375-create-channel-outbound-posts.ts +52 -0
- package/src/persistence/migrations/__tests__/370-acp-session-history-auth-error-code.test.ts +65 -0
- package/src/persistence/migrations/__tests__/371-acp-session-history-auth-error-credential.test.ts +68 -0
- package/src/persistence/migrations/__tests__/372-create-acp-refused-credentials.test.ts +64 -0
- package/src/persistence/migrations/__tests__/373-acp-auth-marker-index.test.ts +82 -0
- package/src/persistence/migrations/__tests__/375-create-channel-outbound-posts.test.ts +84 -0
- package/src/persistence/schema/acp.ts +25 -0
- package/src/persistence/schema/conversations.ts +71 -2
- package/src/persistence/schema-contract.test.ts +78 -0
- package/src/persistence/schema-contract.ts +96 -0
- package/src/persistence/steps.ts +12 -0
- package/src/platform/platform-patch-queue.test.ts +43 -41
- package/src/plugin-api/index.ts +12 -0
- package/src/plugins/defaults/compaction/window-manager.ts +2 -0
- package/src/plugins/defaults/image-recovery/recover.ts +12 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +166 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +3 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +3 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +53 -9
- package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +4 -7
- package/src/plugins/defaults/memory/src/memory-worker-routes.ts +1 -1
- package/src/plugins/defaults/memory/v1/job-handlers/index-maintenance.ts +15 -1
- package/src/plugins/defaults/memory/worker-control.ts +1 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +50 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +49 -2
- package/src/providers/anthropic/client.ts +1 -1
- package/src/providers/call-site-routing.ts +5 -4
- package/src/providers/connection-resolution.ts +29 -1
- package/src/providers/content-block-schema.ts +1 -0
- package/src/providers/fireworks/client.ts +9 -1
- package/src/providers/gemini/client.ts +22 -15
- package/src/providers/inference/auth.ts +6 -6
- package/src/providers/media-resolve.ts +24 -10
- package/src/providers/model-catalog.ts +145 -0
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/chat-completions-provider.ts +44 -5
- package/src/providers/registry.ts +10 -7
- package/src/providers/retry.ts +16 -11
- package/src/providers/routing-identity.ts +2 -1
- package/src/providers/types.ts +56 -0
- package/src/providers/vellum-model-routing.ts +3 -2
- package/src/routes/__tests__/control.test.ts +4 -3
- package/src/routes/control.ts +1 -1
- package/src/routes/route-host-client.ts +1 -1
- package/src/runtime/AGENTS.md +42 -13
- package/src/runtime/__tests__/agent-wake.test.ts +71 -6
- package/src/runtime/__tests__/guardian-form-registry.test.ts +242 -0
- package/src/runtime/access-request-helper.ts +15 -7
- package/src/runtime/agent-wake.ts +16 -4
- package/src/runtime/approval-source-link.ts +6 -0
- package/src/runtime/channel-approval-types.ts +7 -8
- package/src/runtime/channel-invite-transport.ts +2 -0
- package/src/runtime/channel-invite-transports/discord.ts +27 -0
- package/src/runtime/channel-invite-transports/email.ts +10 -9
- package/src/runtime/channel-readiness-service.ts +87 -27
- package/src/runtime/channel-reply-delivery.ts +145 -44
- package/src/runtime/channel-retry-sweep.ts +94 -0
- package/src/runtime/guardian-action-service.ts +9 -5
- package/src/runtime/guardian-form-registry.ts +256 -0
- package/src/runtime/guardian-reply-router.ts +4 -56
- package/src/runtime/invite-instruction-generator.ts +14 -2
- package/src/runtime/migrations/vbundle-metadata-merge.ts +4 -7
- package/src/runtime/no-response.ts +13 -74
- package/src/runtime/question-request-guardian-bridge.ts +1 -2
- package/src/runtime/routes/__tests__/acp-routes.test.ts +527 -0
- package/src/runtime/routes/__tests__/app-management-shared-apps.test.ts +74 -0
- package/src/runtime/routes/__tests__/contact-form-kinds.test.ts +22 -0
- package/src/runtime/routes/__tests__/contact-record-prompt-route.test.ts +303 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +3 -4
- package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +6 -0
- package/src/runtime/routes/__tests__/route-host-worker-routes.test.ts +3 -4
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +5 -6
- package/src/runtime/routes/acp-routes-list.test.ts +58 -0
- package/src/runtime/routes/acp-routes.ts +254 -48
- package/src/runtime/routes/app-management-routes.ts +80 -47
- package/src/runtime/routes/approval-routes.ts +9 -0
- package/src/runtime/routes/archive-utils.ts +6 -1
- package/src/runtime/routes/avatar-routes.ts +1 -1
- package/src/runtime/routes/channel-availability-routes.ts +18 -31
- package/src/runtime/routes/channel-route-shared.ts +3 -44
- package/src/runtime/routes/channel-verification-routes.ts +4 -1
- package/src/runtime/routes/contact-prompt-routes.ts +271 -105
- package/src/runtime/routes/conversation-routes.ts +41 -33
- package/src/runtime/routes/credential-prompt-routes.ts +10 -1
- package/src/runtime/routes/credential-routes.ts +3 -0
- package/src/runtime/routes/debug-bash-routes.ts +1 -0
- package/src/runtime/routes/email-routes.ts +35 -47
- package/src/runtime/routes/guardian-approval-interception.ts +0 -5
- package/src/runtime/routes/guardian-expiry-sweep.ts +89 -31
- package/src/runtime/routes/guardian-form-routes.ts +115 -0
- package/src/runtime/routes/inbound-message-handler.ts +199 -53
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +141 -4
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +77 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +6 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +6 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +24 -44
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +490 -99
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +365 -157
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/channel.ts +39 -18
- package/src/runtime/routes/migration-routes.ts +1 -3
- package/src/runtime/routes/monitoring-routes.ts +0 -3
- package/src/runtime/routes/oauth-commands-routes.ts +18 -5
- package/src/runtime/routes/route-host-worker-routes.ts +1 -1
- package/src/runtime/routes/schedule-worker-routes.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +4 -0
- package/src/runtime/verification-outbound-actions.ts +8 -12
- package/src/schedule/run-script.ts +1 -0
- package/src/schedule/scheduler.ts +1 -1
- package/src/schedule/worker-control.ts +2 -2
- package/src/security/oauth2.ts +2 -11
- package/src/security/secure-keys.ts +55 -8
- package/src/skills/catalog-install.ts +7 -4
- package/src/skills/clawhub.ts +1 -0
- package/src/skills/inline-command-runner.ts +1 -0
- package/src/stt/__tests__/room-noise-floor.test.ts +108 -0
- package/src/stt/room-noise-floor.ts +140 -0
- package/src/subagent/notify.ts +49 -3
- package/src/tools/__tests__/tool-input-schemas.test.ts +2 -0
- package/src/tools/acp/spawn.ts +2 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +9 -0
- package/src/tools/browser/browser-execution.ts +10 -43
- package/src/tools/browser/browser-manager.ts +1 -0
- package/src/tools/browser/browser-status-constants.ts +6 -5
- package/src/tools/browser/runtime-check.ts +2 -0
- package/src/tools/channel/react-to-message.test.ts +193 -0
- package/src/tools/channel/react-to-message.ts +159 -0
- package/src/tools/client-os.ts +9 -0
- package/src/tools/credentials/metadata-store.ts +115 -19
- package/src/tools/credentials/store.ts +3 -2
- package/src/tools/filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.ts +4 -4
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +24 -0
- package/src/tools/host-terminal/host-shell.ts +13 -40
- package/src/tools/shared/filesystem/file-ops-service.ts +10 -7
- package/src/tools/shared/shell-output.test.ts +104 -0
- package/src/tools/shared/shell-output.ts +112 -39
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/skills/sandbox-runner.ts +1 -0
- package/src/tools/system/request-permission.test.ts +34 -0
- package/src/tools/system/request-permission.ts +29 -5
- package/src/tools/terminal/shell.test.ts +63 -0
- package/src/tools/terminal/shell.ts +12 -44
- package/src/tools/tool-input-schemas.ts +2 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/ui-surface/definitions.ts +4 -3
- package/src/usage/attribution.ts +12 -4
- package/src/util/__tests__/worker-ownership.test.ts +77 -0
- package/src/util/__tests__/worker-process-command.test.ts +246 -1
- package/src/util/bun-runtime.ts +44 -13
- package/src/util/bundled-asset.ts +9 -1
- package/src/util/disk-usage.ts +1 -0
- package/src/util/file-use.ts +4 -1
- package/src/util/guardian-form-timeouts.ts +50 -0
- package/src/util/image-conversion.ts +1 -0
- package/src/util/oauth-request-body.test.ts +59 -0
- package/src/util/oauth-request-body.ts +56 -5
- package/src/util/platform.ts +69 -73
- package/src/util/pricing.ts +2 -1
- package/src/util/process-table.ts +16 -5
- package/src/util/read-stdin.ts +5 -0
- package/src/util/spawn.ts +1 -0
- package/src/util/sqlite3-runtime.ts +25 -5
- package/src/util/worker-ownership.ts +193 -0
- package/src/util/worker-process.ts +375 -37
- package/src/workspace/git-service.ts +4 -12
- package/src/workspace/migrations/010-app-dir-rename.ts +1 -0
- package/src/__tests__/slack-reaction-approvals.test.ts +0 -77
- package/src/__tests__/slack-reaction-guardian-approval.test.ts +0 -279
package/ARCHITECTURE.md
CHANGED
|
@@ -120,7 +120,7 @@ Scoped approval grants allow a guardian's approval decision on one channel (e.g.
|
|
|
120
120
|
|
|
121
121
|
### Guardian Decision Primitive
|
|
122
122
|
|
|
123
|
-
All guardian approval decisions
|
|
123
|
+
All guardian approval decisions, regardless of how they arrive, route through a single primitive in `src/approvals/guardian-decision-primitive.ts`, which centralizes decision logic for callback button handlers, the conversational approval engine, and channel text replies.
|
|
124
124
|
|
|
125
125
|
**Core API:**
|
|
126
126
|
|
|
@@ -203,7 +203,7 @@ The guardian request system provides a channel-agnostic, unified domain for all
|
|
|
203
203
|
|
|
204
204
|
**Resolver registry:** Kind-specific resolvers (`src/approvals/guardian-request-resolvers.ts`) handle side effects after CAS resolution. Built-in resolvers: `tool_approval` (channel/desktop approval path), `pending_question` (voice call question path), and `access_request` (trusted-contact verification session creation). New request kinds register resolvers without touching the core primitive.
|
|
205
205
|
|
|
206
|
-
**Expiry:** the daemon's 60-second sweep (`src/runtime/routes/guardian-expiry-sweep.ts`)
|
|
206
|
+
**Expiry:** the daemon's 60-second sweep (`src/runtime/routes/guardian-expiry-sweep.ts`) lists a bounded batch of past-deadline pending requests (`guardian_requests_list_expired_pending`, read-only), fans out card withdrawal + requester notices per row, and only then confirms each with the per-request `guardian_requests_expire` CAS, so a lost response or crash leaves the row listed for the next round; interaction-bound kinds (`tool_approval`, `pending_question`) are expired at daemon boot via `guardian_requests_expire_interaction_bound` since they die with the in-memory pending-interactions map, and the boot call never touches persistent kinds. `src/calls/guardian-action-sweep.ts` sends the guardian-facing expiry notices for voice questions.
|
|
207
207
|
|
|
208
208
|
**Key source files:**
|
|
209
209
|
|
|
@@ -267,19 +267,19 @@ Guardian requests (tool approvals, access requests, voice ASK_GUARDIAN questions
|
|
|
267
267
|
|
|
268
268
|
**Voice consultation timeout:** When a voice call's ASK_GUARDIAN consultation times out before the guardian responds, the call controller expires the request via the gateway (`guardian_requests_expire` — deliveries expire with it), sends expiry notices to every surface the approval card reached (vellum conversations get an assistant message; external channels get a direct channel reply), and injects a `[GUARDIAN_TIMEOUT]` instruction so the model apologizes to the caller and offers a message or callback on the next voice turn.
|
|
269
269
|
|
|
270
|
-
**Background expiry sweep:** Independent of any active call, a 60-second sweep
|
|
270
|
+
**Background expiry sweep:** Independent of any active call, a 60-second sweep lists pending guardian requests past their `expiresAt` (`guardian_requests_list_expired_pending`), runs the side effects per row (withdrawing the approval cards on every surface, notifying the requester, releasing any in-memory pending interaction), and then confirms each with the per-request `guardian_requests_expire` CAS; a decision arriving past the deadline loses to expiry atomically, since the decide CAS guards on `expires_at`.
|
|
271
271
|
|
|
272
272
|
**Generated messaging requirement:** All user-facing copy in the guardian timeout/expiry path is generated through the `guardian-action-message-composer.ts` composition system, which uses a 2-tier priority chain: (1) daemon-injected LLM generator for natural, varied text; (2) deterministic fallback templates for reliability. No hardcoded user-facing strings exist in the flow files outside of internal log messages and LLM-instruction prompts. A guard test (`guardian-action-no-hardcoded-copy.test.ts`) enforces this invariant.
|
|
273
273
|
|
|
274
274
|
**Key source files:**
|
|
275
275
|
|
|
276
|
-
| File | Purpose
|
|
277
|
-
| ------------------------------------------------- |
|
|
278
|
-
| `src/channels/gateway-guardian-requests.ts` | Gateway-backed guardian-request client: typed wrappers over the `guardian_requests_*` IPC routes that own request/delivery state and expiry
|
|
279
|
-
| `src/runtime/routes/guardian-expiry-sweep.ts` | Periodic 60s sweep:
|
|
280
|
-
| `src/calls/call-controller.ts` | Voice timeout handling: expires the request, sends expiry notices, injects `[GUARDIAN_TIMEOUT]` instruction for the generated voice response
|
|
281
|
-
| `src/calls/guardian-action-sweep.ts` | Expiry notice delivery to guardian destinations (vellum conversation message or direct channel reply)
|
|
282
|
-
| `src/runtime/guardian-action-message-composer.ts` | 2-tier text generation: daemon-injected LLM generator with deterministic fallback templates
|
|
276
|
+
| File | Purpose |
|
|
277
|
+
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
278
|
+
| `src/channels/gateway-guardian-requests.ts` | Gateway-backed guardian-request client: typed wrappers over the `guardian_requests_*` IPC routes that own request/delivery state and expiry |
|
|
279
|
+
| `src/runtime/routes/guardian-expiry-sweep.ts` | Periodic 60s sweep: bounded expired-pending list, per-row card-withdrawal, requester-notice, and pending-interaction fan-out, then per-request expire CAS |
|
|
280
|
+
| `src/calls/call-controller.ts` | Voice timeout handling: expires the request, sends expiry notices, injects `[GUARDIAN_TIMEOUT]` instruction for the generated voice response |
|
|
281
|
+
| `src/calls/guardian-action-sweep.ts` | Expiry notice delivery to guardian destinations (vellum conversation message or direct channel reply) |
|
|
282
|
+
| `src/runtime/guardian-action-message-composer.ts` | 2-tier text generation: daemon-injected LLM generator with deterministic fallback templates |
|
|
283
283
|
|
|
284
284
|
### WhatsApp Channel (Meta Cloud API)
|
|
285
285
|
|
|
@@ -2066,7 +2066,7 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2066
2066
|
| ---------------------------------------- | ------------------------------------------------------ | ----------------------------------- | ---------------------------------- | ------------------------------------------------------- |
|
|
2067
2067
|
| API key | CES / encrypted file store | Encrypted binary | CES API / `secure-keys.ts` | Permanent |
|
|
2068
2068
|
| Credential secrets | CES / encrypted file store | Encrypted binary | `secure-keys.ts` wrapper | Permanent (until deleted via tool) |
|
|
2069
|
-
| Credential
|
|
2069
|
+
| Credential records | CES `<cesDataRoot>/metadata.json` | JSON | CES RPC/HTTP + atomic file write | Permanent (until deleted via tool) |
|
|
2070
2070
|
| Integration OAuth tokens | CES / encrypted file store (via `secure-keys.ts`) | Encrypted binary | `TokenManager` auto-refresh | Until disconnected or revoked |
|
|
2071
2071
|
| User preferences | UserDefaults | plist | Foundation | Permanent |
|
|
2072
2072
|
| Session logs | `~/Library/.../logs/session-*.json` | JSON per session | Swift Codable | Unbounded |
|
package/Dockerfile
CHANGED
|
@@ -117,6 +117,7 @@ RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx
|
|
|
117
117
|
COPY --from=builder /app /app
|
|
118
118
|
|
|
119
119
|
# Copy source after installing dependencies for better layer caching.
|
|
120
|
+
COPY packages/avatar-catalog /app/packages/avatar-catalog
|
|
120
121
|
COPY packages/avatar-manifest /app/packages/avatar-manifest
|
|
121
122
|
COPY packages/ces-client /app/packages/ces-client
|
|
122
123
|
COPY packages/service-contracts /app/packages/service-contracts
|
|
@@ -229,7 +229,7 @@ User messages are scanned at ingress (`secret-ingress.ts`) against known credent
|
|
|
229
229
|
| Component | Location | What it stores |
|
|
230
230
|
| ------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
231
231
|
| Secret values | CES credential store or encrypted file store | Encrypted credential values keyed as `credential/{service}/{field}`. Stored via CES RPC (primary), CES HTTP (containerized), or encrypted file store (fallback). |
|
|
232
|
-
| Credential
|
|
232
|
+
| Credential records | CES `<cesDataRoot>/metadata.json` | Service, field, alias, policy (`allowedTools`, `allowedDomains`, `injectionTemplates`), timestamps. Served over CES RPC/HTTP. |
|
|
233
233
|
| Config | `$VELLUM_WORKSPACE_DIR/config.*` | `secretDetection` settings: enabled, blockIngress, allowOneTimeSend, blockTokenShapedMessages (default `true` — whole-message token-shape heuristic) |
|
|
234
234
|
|
|
235
235
|
### Key Files
|
package/docs/error-handling.md
CHANGED
|
@@ -52,7 +52,7 @@ interface ToolExecutionResult {
|
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Existing examples: `EditEngineResult` in `edit-engine.ts`, `PathResult` in `path-policy.ts`, `ToolExecutionResult` in `tools/types.ts
|
|
55
|
+
Existing examples: `EditEngineResult` in `edit-engine.ts`, `PathResult` in `path-policy.ts`, `ToolExecutionResult` in `tools/types.ts`.
|
|
56
56
|
|
|
57
57
|
## 3. Never return null/undefined to indicate failure
|
|
58
58
|
|
|
@@ -66,7 +66,6 @@ Returning `undefined` is acceptable only for **lookup functions** where "not fou
|
|
|
66
66
|
| ----------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
67
67
|
| Agent loop (`agent/loop.ts`) | Throws + catch-and-emit | Unrecoverable provider errors break the loop; expected errors (abort, tool-use limits) are caught and emitted as events |
|
|
68
68
|
| Tool executor (`tools/executor.ts`) | Result object (`ToolExecutionResult`) | Tool failures are expected operational outcomes — permission denied, unknown tool, sandbox violations. Never throws to callers |
|
|
69
|
-
| Memory retriever (`memory/retriever.ts`) | Result object (`MemoryRecallResult`) with degraded/reason fields | Graceful degradation — embedding failures, search failures degrade quality without crashing |
|
|
70
69
|
| Filesystem tools (`path-policy.ts`, `edit-engine.ts`) | Discriminated union (`{ ok, reason }`) | Validation outcomes that the caller must handle (out of bounds, not found, ambiguous) |
|
|
71
70
|
| Subagent manager (`subagent/manager.ts`) | Throws for precondition violations, string literal unions for expected outcomes | Depth limit exceeded is a bug; `sendMessage` returns `'not_found' \| 'terminal' \| 'queue_full'` as expected states |
|
|
72
71
|
| Interactive UI (`cli/commands/ui.ts`) | Result object (`InteractiveUiResult`) with `status` + exit codes | User cancel and timeout are expected operational outcomes, not errors. IPC failures are exceptional. |
|
|
@@ -28,10 +28,10 @@ anti-pattern was retired in #35642 and again in the ask_question redesign).
|
|
|
28
28
|
telegram: inline keyboard; slack: blocks; vellum: conversation card via approval-card-builder)
|
|
29
29
|
card deliveries recorded per channel (guardian-delivery-recorder.ts → guardian_request_deliveries)
|
|
30
30
|
│
|
|
31
|
-
▼ user responds: button tap /
|
|
31
|
+
▼ user responds: button tap / "CODE <reply>" / bare text
|
|
32
32
|
guardian reply router (runtime/guardian-reply-router.ts, invoked from
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
callbacks → request codes → bare answer → routes/inbound-stages/guardian-reply-intercept.ts,
|
|
34
|
+
explicit approve/reject → NL BEFORE background dispatch: replies to parked
|
|
35
35
|
│ prompts resolve inline, never deferred)
|
|
36
36
|
▼ one decision primitive
|
|
37
37
|
applyGuardianDecision (approvals/guardian-decision-primitive.ts:
|
|
@@ -45,24 +45,63 @@ anti-pattern was retired in #35642 and again in the ask_question redesign).
|
|
|
45
45
|
|
|
46
46
|
## Who owns what
|
|
47
47
|
|
|
48
|
-
| Concern | Owner
|
|
49
|
-
| --------------------------------------- |
|
|
50
|
-
| The "what": card text, actions, options | broadcaster context build (once per broadcast)
|
|
51
|
-
| The "how": channel-native rendering | `notifications/adapters/<channel>`
|
|
52
|
-
| Request state | gateway `guardian_requests` (+ deliveries)
|
|
53
|
-
| Decisions | `applyGuardianDecision` (CAS, atomic ACL outcome)
|
|
54
|
-
| Kind-specific follow-through | resolver registry (`kind` → resolver)
|
|
55
|
-
| Reply understanding | guardian reply router (codes, buttons,
|
|
48
|
+
| Concern | Owner | Never |
|
|
49
|
+
| --------------------------------------- | ------------------------------------------------- | ----------------------------------- |
|
|
50
|
+
| The "what": card text, actions, options | broadcaster context build (once per broadcast) | built per-adapter |
|
|
51
|
+
| The "how": channel-native rendering | `notifications/adapters/<channel>` | domain logic, payload parsing |
|
|
52
|
+
| Request state | gateway `guardian_requests` (+ deliveries) | daemon-side request tables |
|
|
53
|
+
| Decisions | `applyGuardianDecision` (CAS, atomic ACL outcome) | inline decision logic at call sites |
|
|
54
|
+
| Kind-specific follow-through | resolver registry (`kind` → resolver) | switch statements in the router |
|
|
55
|
+
| Reply understanding | guardian reply router (codes, buttons, modes) | per-feature inbound intercepts |
|
|
56
|
+
|
|
57
|
+
## The canonical home-feed projection
|
|
58
|
+
|
|
59
|
+
Every pending request is also exactly one home-feed item, the bell's
|
|
60
|
+
"Needs attention" row. `notifications/guardian-feed-projection.ts` owns
|
|
61
|
+
it end to end:
|
|
62
|
+
|
|
63
|
+
- The pipeline's feed side effect writes it keyed
|
|
64
|
+
`guardian:<requestId>`, so the feed's replace-in-place merge keeps one
|
|
65
|
+
item per request. Its typed `guardianRequest` field
|
|
66
|
+
(`FeedItemGuardianRequestSchema` in `api/responses/home.ts`) is a read
|
|
67
|
+
projection of the gateway row: intent, status, requester, tool, and
|
|
68
|
+
source reference. It is never a delivery row of its own; clients
|
|
69
|
+
derive every affordance from `status`.
|
|
70
|
+
- `withdrawGuardianRequestCards` rewrites it into a terminal receipt as
|
|
71
|
+
one of the surfaces it settles, and its failure gates `complete` the
|
|
72
|
+
same way a failed card edit does. The write-vs-resolve race converges
|
|
73
|
+
from the other side too: the feed writer re-checks canonical status
|
|
74
|
+
after its append.
|
|
75
|
+
- The feed writer's bulk-dismiss pass skips pending guardian items
|
|
76
|
+
(`isPendingGuardianFeedItem`), so "Clear all" can never retire an
|
|
77
|
+
unresolved request; only its receipt is clearable.
|
|
78
|
+
- The guardian expiry sweep runs `reconcileGuardianFeedProjections()`
|
|
79
|
+
each round: pending requests missing an item are backfilled from the
|
|
80
|
+
request row (no conversation is generated), and an item still
|
|
81
|
+
actionable for a terminal request is receipted with a loud log line.
|
|
82
|
+
|
|
83
|
+
Routing policy for channel-delivered cards: a guardian card sent to a
|
|
84
|
+
channel chat (Slack, Telegram, Discord, WhatsApp) is a delivery
|
|
85
|
+
projection, not conversation content. Channel deliveries are not
|
|
86
|
+
paired with any conversation (`conversation-pairing.ts` skips every
|
|
87
|
+
non-vellum guardian delivery), and the Slack DM cold backfill skips
|
|
88
|
+
messages whose ts matches a recorded guardian delivery for the chat
|
|
89
|
+
(`guardian_requests_list_deliveries_by_chat`), so a card never enters
|
|
90
|
+
a Vellum transcript. The in-app homes of a request are the feed item
|
|
91
|
+
and the source conversation's pinned vellum card.
|
|
56
92
|
|
|
57
93
|
## Cards are not conversation history
|
|
58
94
|
|
|
59
|
-
`pairDeliveryWithConversation` persists one message row
|
|
60
|
-
card renders and deep-links.
|
|
95
|
+
`pairDeliveryWithConversation` persists one message row for the vellum
|
|
96
|
+
delivery so the card renders and deep-links. That row is addressed to a
|
|
61
97
|
conversation the request is _about_, not one the assistant is speaking in:
|
|
62
98
|
`buildVellumCardAffinity` pins the vellum card to the originating
|
|
63
|
-
conversation
|
|
64
|
-
|
|
65
|
-
notification pipeline, so the live turn's
|
|
99
|
+
conversation. Channel guardian deliveries pair no conversation (see the
|
|
100
|
+
routing policy above), so the vellum row is the only card row written; it
|
|
101
|
+
goes straight to the DB by the notification pipeline, so the live turn's
|
|
102
|
+
in-memory history never sees it. Rows that channel deliveries paired
|
|
103
|
+
before the projection-only policy still exist and are covered by the same
|
|
104
|
+
filter below.
|
|
66
105
|
|
|
67
106
|
That row must never be replayed to the model. The conversation it lands in is
|
|
68
107
|
typically parked mid-approval, with its last assistant message carrying the
|
|
@@ -147,8 +186,8 @@ chat the turn is running in. On Slack that chat can be a shared room, and the
|
|
|
147
186
|
card carries the tool, a command preview and live buttons.
|
|
148
187
|
`resolveGuardianPromptDelivery` addresses it to the guardian's bound DM
|
|
149
188
|
instead, by chat id rather than user id because that address is written to the
|
|
150
|
-
delivery row and read back to
|
|
151
|
-
|
|
189
|
+
delivery row and read back to scope plain-text replies and edit the decided
|
|
190
|
+
card. It returns the address and its route together, since
|
|
152
191
|
the turn's own callback carries a `threadTs` naming a thread that does not
|
|
153
192
|
exist in the DM. When no private address resolves it returns nothing and the
|
|
154
193
|
prompt is left to the in-app confirmation, because the room is the disclosure
|
|
@@ -156,3 +195,10 @@ this exists to prevent. Telegram group chats carry the same exposure and are
|
|
|
156
195
|
not covered: only Slack has a chat whose privacy can be read off its id. They remain load-bearing for that flow, and
|
|
157
196
|
the reply router runs first for everything the pipeline owns. Converge new
|
|
158
197
|
work on the pipeline; do not extend the legacy interception.
|
|
198
|
+
|
|
199
|
+
Any flow that resolves a confirmation in-memory first (this rail, the in-app
|
|
200
|
+
`/v1/confirm` route, the auto-deny sweeps) brings the gateway row to the
|
|
201
|
+
matching terminal status through `approvals/guardian-request-status-sync.ts`,
|
|
202
|
+
which also runs the same cross-surface card withdrawal the decision primitive
|
|
203
|
+
runs whenever its CAS is the one that landed: no projection of a resolved
|
|
204
|
+
request may stay actionable, whichever rail resolved it.
|
|
@@ -68,12 +68,12 @@ requested -> pending_guardian -> verification_pending -> active | denied | expir
|
|
|
68
68
|
|
|
69
69
|
Identity binding ensures the verification code can only be consumed by the intended recipient on the intended channel. The binding fields are set on the gateway `channel_verification_sessions` record when the session is created; the check itself is `checkIdentityMatch` (`gateway/src/verification/identity-match.ts`).
|
|
70
70
|
|
|
71
|
-
| Channel | Identity fields
|
|
72
|
-
| --------- |
|
|
73
|
-
| Telegram | `expectedExternalUserId` = Telegram user ID, `expectedChatId` = Telegram chat ID
|
|
74
|
-
| Voice | `expectedPhoneE164` = phone number in E.164 format
|
|
71
|
+
| Channel | Identity fields | Binding behavior |
|
|
72
|
+
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| Telegram | `expectedExternalUserId` = Telegram user ID, `expectedChatId` = Telegram chat ID | Both are taken from the original denied message's metadata. The `identityBindingStatus` is `'bound'`. Verification requires the actor's user ID or chat ID to match (user ID required when both are set on a shared chat). |
|
|
74
|
+
| Voice | `expectedPhoneE164` = phone number in E.164 format | Phone-based identity binding. Verification requires the caller's number to match the expected phone. |
|
|
75
75
|
| Discord | `expectedExternalUserId` = Discord user snowflake. `expectedChatId` is unset on the guardian-initiated and trusted-contact paths, and is the originating guild channel on the access-request approval path (`mint_outbound_session`), which sets it for every channel alike. | The code is delivered to a DM and answered there, but the DM channel does not exist until it is opened, so those two paths have no chat id to record at mint time. Where the approval path does set one, it is a room rather than an identity and never becomes a sufficient credential on its own: `checkIdentityMatch` requires the `expectedExternalUserId` match whenever both fields are set. That path also writes the room into `destinationAddress`, where it describes nothing the code is ever sent to (see LUM-3110). |
|
|
76
|
-
| Bootstrap | none yet (`identityBindingStatus: 'pending_bootstrap'`)
|
|
76
|
+
| Bootstrap | none yet (`identityBindingStatus: 'pending_bootstrap'`) | Unbound deep-link sessions use a 32-byte hex token instead of a numeric code; the identity is bound when the token is redeemed (`verification_sessions_bind_identity`). |
|
|
77
77
|
|
|
78
78
|
**Anti-oracle invariant:** When identity verification fails, the error message is identical to the "invalid or expired code" message. This prevents attackers from distinguishing between a wrong code and a wrong identity, which would leak information about which identities have pending sessions.
|
|
79
79
|
|
|
@@ -129,10 +129,10 @@ Separately, the admitted-mode introduction **nudge** (for a contact who cleared
|
|
|
129
129
|
|
|
130
130
|
### Stage: `expired`
|
|
131
131
|
|
|
132
|
-
| Store | Table | Record
|
|
133
|
-
| ------------------------------------------------ | ------------------------------- |
|
|
134
|
-
| gateway `guardian-request-store.ts` (gateway DB) | `guardian_requests` | Updated to `status: 'expired'` via `
|
|
135
|
-
| `session-store.ts` (gateway DB) | `channel_verification_sessions` | Expires naturally: `expiresAt < Date.now()` makes it invisible to `findPendingSessionByHash()`.
|
|
132
|
+
| Store | Table | Record |
|
|
133
|
+
| ------------------------------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
134
|
+
| gateway `guardian-request-store.ts` (gateway DB) | `guardian_requests` | Updated to `status: 'expired'` via the per-request `guardian_requests_expire` CAS, after the daemon's 60s sweep has run that row's side effects. |
|
|
135
|
+
| `session-store.ts` (gateway DB) | `channel_verification_sessions` | Expires naturally: `expiresAt < Date.now()` makes it invisible to `findPendingSessionByHash()`. |
|
|
136
136
|
|
|
137
137
|
### Invites (alternative path)
|
|
138
138
|
|
|
@@ -216,10 +216,11 @@ sequenceDiagram
|
|
|
216
216
|
|
|
217
217
|
else Guardian never responds
|
|
218
218
|
Note over A: runGuardianExpirySweep()<br/>runs every 60 seconds
|
|
219
|
-
A->>GW:
|
|
220
|
-
GW->>GW: Approval TTL elapsed → status: 'expired' (CAS)
|
|
219
|
+
A->>GW: guardian_requests_list_expired_pending (IPC)
|
|
221
220
|
A->>A: Withdraw approval cards on all surfaces
|
|
222
221
|
A-->>U: "Your access request has expired."
|
|
222
|
+
A->>GW: guardian_requests_expire (IPC)
|
|
223
|
+
GW->>GW: status: 'expired' (CAS, the fan-out's receipt)
|
|
223
224
|
|
|
224
225
|
else Code expires (requester never enters it)
|
|
225
226
|
Note over GW: Verification session TTL: 10 min
|
|
@@ -232,7 +233,7 @@ sequenceDiagram
|
|
|
232
233
|
|
|
233
234
|
### Guardian never responds
|
|
234
235
|
|
|
235
|
-
- The `runGuardianExpirySweep()` timer (`runtime/routes/guardian-expiry-sweep.ts`) runs every 60 seconds; the gateway
|
|
236
|
+
- The `runGuardianExpirySweep()` timer (`runtime/routes/guardian-expiry-sweep.ts`) runs every 60 seconds; the gateway returns a bounded, read-only batch of pending requests past their `expiresAt` (`guardian_requests_list_expired_pending`), and the daemon confirms each row with the per-request `guardian_requests_expire` CAS only after running its side effects, so the fan-out is recoverable from state.
|
|
236
237
|
- The daemon then withdraws the now-stale approval cards on every surface and notifies the requester that the request expired.
|
|
237
238
|
|
|
238
239
|
### Verification code expires
|
package/knip.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vellumai/avatar-catalog",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts",
|
|
9
|
+
"./colors": "./src/colors.ts"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"typecheck": "bunx tsc --noEmit",
|
|
13
|
+
"test": "bun test src/"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/bun": "1.3.11",
|
|
17
|
+
"typescript": "5.9.3"
|
|
18
|
+
}
|
|
19
|
+
}
|
package/{src/avatar/character-components.ts → node_modules/@vellumai/avatar-catalog/src/catalog.ts}
RENAMED
|
@@ -1,43 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
viewBox: { width: number; height: number };
|
|
4
|
-
faceCenter: { x: number; y: number };
|
|
5
|
-
svgPath: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface EyePathDefinition {
|
|
9
|
-
svgPath: string;
|
|
10
|
-
color: string; // hex e.g. "#F2F2F2"
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface EyeStyleDefinition {
|
|
14
|
-
id: string;
|
|
15
|
-
sourceViewBox: { width: number; height: number };
|
|
16
|
-
eyeCenter: { x: number; y: number };
|
|
17
|
-
paths: EyePathDefinition[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface ColorDefinition {
|
|
21
|
-
id: string;
|
|
22
|
-
hex: string; // e.g. "#4C9B50"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface FaceCenterOverride {
|
|
26
|
-
bodyShape: string;
|
|
27
|
-
eyeStyle: string;
|
|
28
|
-
faceCenter: { x: number; y: number };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface CharacterComponents {
|
|
32
|
-
bodyShapes: BodyShapeDefinition[];
|
|
33
|
-
eyeStyles: EyeStyleDefinition[];
|
|
34
|
-
colors: ColorDefinition[];
|
|
35
|
-
faceCenterOverrides: FaceCenterOverride[];
|
|
36
|
-
}
|
|
1
|
+
import { AVATAR_COLORS } from "./colors.js";
|
|
2
|
+
import type { CharacterComponents } from "./types.js";
|
|
37
3
|
|
|
38
4
|
const SCLERA = "#F2F2F2";
|
|
39
5
|
const PUPIL = "#1A1A1A";
|
|
40
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Every body shape, eye style, and face-centre override an avatar can be
|
|
9
|
+
* composed from, plus the palette re-exposed on `colors`.
|
|
10
|
+
*
|
|
11
|
+
* This is the single definition. The daemon serves it over
|
|
12
|
+
* `/avatar/character-components`; clients that must compose an avatar before
|
|
13
|
+
* the daemon answers (a hatching screen, a chooser card) import it directly
|
|
14
|
+
* so no copy has to be kept in step with this one.
|
|
15
|
+
*/
|
|
41
16
|
export function getCharacterComponents(): CharacterComponents {
|
|
42
17
|
return {
|
|
43
18
|
bodyShapes: [
|
|
@@ -369,14 +344,7 @@ export function getCharacterComponents(): CharacterComponents {
|
|
|
369
344
|
},
|
|
370
345
|
],
|
|
371
346
|
|
|
372
|
-
colors:
|
|
373
|
-
{ id: "green", hex: "#4C9B50" },
|
|
374
|
-
{ id: "orange", hex: "#E9642F" },
|
|
375
|
-
{ id: "pink", hex: "#DB4B77" },
|
|
376
|
-
{ id: "purple", hex: "#A665C9" },
|
|
377
|
-
{ id: "teal", hex: "#0E9B8B" },
|
|
378
|
-
{ id: "yellow", hex: "#E9C91A" },
|
|
379
|
-
],
|
|
347
|
+
colors: AVATAR_COLORS,
|
|
380
348
|
|
|
381
349
|
faceCenterOverrides: [
|
|
382
350
|
// Ghost body — shift non-native eyes from y=167 -> y=200
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ColorDefinition } from "./types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The avatar colour palette, in the order the picker offers it.
|
|
5
|
+
*
|
|
6
|
+
* Its own module because the palette is the one part of the catalog that
|
|
7
|
+
* boot-path code needs: a sidebar pin resolves a stored colour id on first
|
|
8
|
+
* render, and the accent CSS variable falls back to the first entry before
|
|
9
|
+
* the daemon's own catalog arrives. Importing the shapes to reach six hex
|
|
10
|
+
* values would put ~47 kB of SVG path data on that path.
|
|
11
|
+
*/
|
|
12
|
+
export const AVATAR_COLORS: ColorDefinition[] = [
|
|
13
|
+
{ id: "green", hex: "#4C9B50" },
|
|
14
|
+
{ id: "orange", hex: "#E9642F" },
|
|
15
|
+
{ id: "pink", hex: "#DB4B77" },
|
|
16
|
+
{ id: "purple", hex: "#A665C9" },
|
|
17
|
+
{ id: "teal", hex: "#0E9B8B" },
|
|
18
|
+
{ id: "yellow", hex: "#E9C91A" },
|
|
19
|
+
];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vellumai/avatar-catalog: the single definition of the components an
|
|
3
|
+
* assistant's character avatar is composed from.
|
|
4
|
+
*
|
|
5
|
+
* The daemon serves this catalog over `/avatar/character-components` and
|
|
6
|
+
* renders PNGs from it; clients bundle it because an avatar has to compose
|
|
7
|
+
* before the daemon can answer (the hatching screen, the assistant chooser,
|
|
8
|
+
* a transcript's subagent chips). Bundling is why this is a package rather
|
|
9
|
+
* than a daemon module every client copies.
|
|
10
|
+
*
|
|
11
|
+
* The palette is deliberately not re-exported here. It lives behind
|
|
12
|
+
* `@vellumai/avatar-catalog/colors`, and importing it from that subpath is
|
|
13
|
+
* what keeps boot-path code (a sidebar pin resolving a stored colour id, the
|
|
14
|
+
* accent variable's fallback) off the ~47 kB of SVG path data the shapes
|
|
15
|
+
* carry. Re-exporting it would make the expensive import the convenient one.
|
|
16
|
+
*
|
|
17
|
+
* The shapes' types stay internal for the same reason they were private to
|
|
18
|
+
* the daemon module this package replaces: the wire contract for this data is
|
|
19
|
+
* the route's `responseBody` schema, which clients consume through their
|
|
20
|
+
* generated OpenAPI types. A hand-written type exported from here would be a
|
|
21
|
+
* second name for that shape, and the closer one to reach for.
|
|
22
|
+
*
|
|
23
|
+
* Leaf package: no dependencies, no runtime imports.
|
|
24
|
+
*/
|
|
25
|
+
export { getCharacterComponents } from "./catalog.js";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shapes for the catalog literal in this package.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than derived from the generated OpenAPI types because
|
|
5
|
+
* this is a leaf package with no dependencies, and the clients that consume
|
|
6
|
+
* those generated types depend on it rather than the other way round. The
|
|
7
|
+
* canonical wire shape is the `avatar/character-components` route's
|
|
8
|
+
* `responseBody` schema; these are not exported so no consumer picks them up
|
|
9
|
+
* as a second name for it.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export interface BodyShapeDefinition {
|
|
13
|
+
id: string;
|
|
14
|
+
viewBox: { width: number; height: number };
|
|
15
|
+
faceCenter: { x: number; y: number };
|
|
16
|
+
svgPath: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface EyePathDefinition {
|
|
20
|
+
svgPath: string;
|
|
21
|
+
color: string; // hex e.g. "#F2F2F2"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface EyeStyleDefinition {
|
|
25
|
+
id: string;
|
|
26
|
+
sourceViewBox: { width: number; height: number };
|
|
27
|
+
eyeCenter: { x: number; y: number };
|
|
28
|
+
paths: EyePathDefinition[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ColorDefinition {
|
|
32
|
+
id: string;
|
|
33
|
+
hex: string; // e.g. "#4C9B50"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface FaceCenterOverride {
|
|
37
|
+
bodyShape: string;
|
|
38
|
+
eyeStyle: string;
|
|
39
|
+
faceCenter: { x: number; y: number };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface CharacterComponents {
|
|
43
|
+
bodyShapes: BodyShapeDefinition[];
|
|
44
|
+
eyeStyles: EyeStyleDefinition[];
|
|
45
|
+
colors: ColorDefinition[];
|
|
46
|
+
faceCenterOverrides: FaceCenterOverride[];
|
|
47
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"outDir": "./dist",
|
|
15
|
+
"rootDir": "./src",
|
|
16
|
+
"types": ["bun"]
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"./client-metadata": "./src/client-metadata.ts",
|
|
12
12
|
"./credential-rpc": "./src/credential-rpc.ts",
|
|
13
13
|
"./ingress": "./src/ingress.ts",
|
|
14
|
+
"./no-response": "./src/no-response.ts",
|
|
14
15
|
"./remote-web-pairing": "./src/remote-web-pairing.ts",
|
|
15
16
|
"./twilio-ingress": "./src/twilio-ingress.ts",
|
|
16
17
|
"./trust-rules": "./src/trust-rules.ts",
|
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts
CHANGED
|
@@ -66,6 +66,13 @@ export function isChannelId(value: unknown): value is ChannelId {
|
|
|
66
66
|
* That irregularity is why this is stated rather than derived from the key,
|
|
67
67
|
* and it is stated here because this file already owns what a channel is.
|
|
68
68
|
*
|
|
69
|
+
* Both senses can hold a user token, which is the sharpest edge. The `slack`
|
|
70
|
+
* integration's persisted token *is* the installer's user token, held on its
|
|
71
|
+
* OAuth connection. `slack_channel` holds an optional `user_token` in the
|
|
72
|
+
* credential store, beside its bot and app tokens. Same words, different
|
|
73
|
+
* homes, and only the second is a credential-store key: a pasted token is
|
|
74
|
+
* always the channel's, because the integration's never leaves the exchange.
|
|
75
|
+
*
|
|
69
76
|
* Deliberately only the key. What fields each credential requires is declared
|
|
70
77
|
* once already, per service, in the gateway's credential specs; restating it
|
|
71
78
|
* here would be a second copy of a different fact.
|
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export * from "./handles.js";
|
|
|
27
27
|
export * from "./rpc.js";
|
|
28
28
|
export * from "./trust-rules.js";
|
|
29
29
|
export * from "./ingress.js";
|
|
30
|
+
export * from "./no-response.js";
|
|
30
31
|
export * from "./remote-web-pairing.js";
|
|
31
32
|
export * from "./twilio-ingress.js";
|
|
32
33
|
export * from "./url-normalization.js";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<no_response/>` sentinel: the cross-service convention for a turn
|
|
3
|
+
* that deliberately produces no user-visible reply.
|
|
4
|
+
*
|
|
5
|
+
* The model emits it, the daemon stamps and strips it, channel delivery
|
|
6
|
+
* suppresses it, and clients hold live-streamed prefixes of it back from
|
|
7
|
+
* display. One definition here keeps every consumer's parsing identical;
|
|
8
|
+
* a hand-rolled copy in any one of them is how the case-sensitivity of a
|
|
9
|
+
* regex drifts.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** Matches a message whose entire content is the sentinel. */
|
|
13
|
+
const NO_RESPONSE_ONLY_RE = /^\s*<no_response\s*\/?>\s*$/i;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether `text` is nothing but the sentinel: the whole reply is a
|
|
17
|
+
* deliberate non-response, as opposed to real content with an inline
|
|
18
|
+
* sentinel mixed in.
|
|
19
|
+
*/
|
|
20
|
+
export function isNoResponseOnlyText(text: string): boolean {
|
|
21
|
+
return NO_RESPONSE_ONLY_RE.test(text);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Matches every sentinel occurrence for stripping it out of mixed content. */
|
|
25
|
+
export const NO_RESPONSE_INLINE_RE = /<no_response\s*\/?>/gi;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Detection variant without the `g` flag: a `g`-flagged regex is stateful
|
|
29
|
+
* under `.test()` (it resumes from `lastIndex`), so reusing
|
|
30
|
+
* {@link NO_RESPONSE_INLINE_RE} for detection would alternate between
|
|
31
|
+
* matches and misses across calls.
|
|
32
|
+
*/
|
|
33
|
+
const NO_RESPONSE_MARKER_RE = new RegExp(NO_RESPONSE_INLINE_RE.source, "i");
|
|
34
|
+
|
|
35
|
+
/** Whether `text` contains the sentinel anywhere. */
|
|
36
|
+
export function containsNoResponseMarker(text: string): boolean {
|
|
37
|
+
return NO_RESPONSE_MARKER_RE.test(text);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Removes every sentinel occurrence, trimming the leftover whitespace. */
|
|
41
|
+
export function stripNoResponseMarkers(text: string): string {
|
|
42
|
+
return text.replace(NO_RESPONSE_INLINE_RE, "").trim();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const NO_RESPONSE_SENTINEL_FORMS = [
|
|
46
|
+
"<no_response/>",
|
|
47
|
+
"<no_response />",
|
|
48
|
+
"<no_response>",
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whether `text` could still grow into the sentinel, i.e. it is a leading
|
|
53
|
+
* substring of one of its forms. Holding on these keeps a slowly-streamed
|
|
54
|
+
* `<no_response/>` from surfacing as visible partial content.
|
|
55
|
+
*/
|
|
56
|
+
export function isPotentialNoResponsePrefix(text: string): boolean {
|
|
57
|
+
const lower = text.trim().toLowerCase();
|
|
58
|
+
if (lower.length === 0) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return NO_RESPONSE_SENTINEL_FORMS.some((sentinel) =>
|
|
62
|
+
sentinel.startsWith(lower),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether `text` carries user-visible content worth acting on now. Returns
|
|
68
|
+
* `false` for empty text, the standalone sentinel, and any prefix that could
|
|
69
|
+
* still complete into one; returns `true` once real content remains after
|
|
70
|
+
* stripping inline sentinels.
|
|
71
|
+
*/
|
|
72
|
+
export function hasDeliverableAssistantText(text: string): boolean {
|
|
73
|
+
const trimmed = text.trim();
|
|
74
|
+
if (trimmed.length === 0) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (NO_RESPONSE_ONLY_RE.test(trimmed)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (isPotentialNoResponsePrefix(trimmed)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return stripNoResponseMarkers(trimmed).length > 0;
|
|
84
|
+
}
|