@vellumai/assistant 0.5.10 → 0.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -0
- package/ARCHITECTURE.md +43 -43
- package/Dockerfile +3 -0
- package/docs/architecture/integrations.md +37 -42
- package/docs/architecture/memory.md +7 -12
- package/docs/credential-execution-service.md +9 -9
- package/docs/skills.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/grants.test.ts +7 -7
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +5 -4
- package/node_modules/@vellumai/credential-storage/src/index.ts +3 -3
- package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +1 -1
- package/openapi.yaml +7208 -0
- package/package.json +2 -1
- package/scripts/generate-openapi.ts +562 -0
- package/src/__tests__/acp-session.test.ts +239 -44
- package/src/__tests__/assistant-feature-flag-guard.test.ts +8 -8
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +5 -86
- package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -14
- package/src/__tests__/browser-skill-endstate.test.ts +1 -1
- package/src/__tests__/btw-routes.test.ts +8 -0
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +10 -10
- package/src/__tests__/catalog-cache.test.ts +164 -0
- package/src/__tests__/catalog-search.test.ts +61 -0
- package/src/__tests__/channel-approvals.test.ts +7 -7
- package/src/__tests__/channel-readiness-service.test.ts +41 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +181 -6
- package/src/__tests__/config-schema.test.ts +10 -2
- package/src/__tests__/context-memory-e2e.test.ts +2 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +396 -0
- package/src/__tests__/conversation-error.test.ts +3 -2
- package/src/__tests__/conversation-skill-tools.test.ts +1 -3
- package/src/__tests__/conversation-title-service.test.ts +2 -15
- package/src/__tests__/credential-execution-feature-gates.test.ts +4 -8
- package/src/__tests__/credential-execution-managed-contract.test.ts +8 -8
- package/src/__tests__/credential-security-e2e.test.ts +4 -4
- package/src/__tests__/credential-security-invariants.test.ts +12 -18
- package/src/__tests__/credential-vault-unit.test.ts +32 -34
- package/src/__tests__/credential-vault.test.ts +25 -33
- package/src/__tests__/credentials-cli.test.ts +3 -3
- package/src/__tests__/daemon-credential-client.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/heartbeat-service.test.ts +35 -0
- package/src/__tests__/host-bash-proxy.test.ts +79 -0
- package/src/__tests__/host-cu-proxy.test.ts +90 -0
- package/src/__tests__/host-file-proxy.test.ts +89 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +3 -3
- package/src/__tests__/integration-status.test.ts +5 -5
- package/src/__tests__/list-messages-attachments.test.ts +171 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +64 -0
- package/src/__tests__/log-export-workspace.test.ts +1 -1
- package/src/__tests__/mcp-abort-signal.test.ts +205 -0
- package/src/__tests__/mcp-client-auth.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
- package/src/__tests__/memory-recall-log-store.test.ts +182 -0
- package/src/__tests__/memory-recall-quality.test.ts +6 -8
- package/src/__tests__/memory-regressions.test.ts +53 -42
- package/src/__tests__/memory-retrieval.benchmark.test.ts +5 -9
- package/src/__tests__/messaging-send-tool.test.ts +5 -5
- package/src/__tests__/messaging-skill-split.test.ts +2 -17
- package/src/__tests__/notification-telegram-adapter.test.ts +125 -0
- package/src/__tests__/oauth-cli.test.ts +203 -649
- package/src/__tests__/oauth-provider-profiles.test.ts +55 -20
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/onboarding-template-contract.test.ts +2 -2
- package/src/__tests__/platform-callback-registration.test.ts +119 -0
- package/src/__tests__/secret-ingress-channel.test.ts +261 -0
- package/src/__tests__/secret-ingress-cli.test.ts +201 -0
- package/src/__tests__/secret-ingress-http.test.ts +312 -0
- package/src/__tests__/secret-ingress.test.ts +283 -0
- package/src/__tests__/secret-onetime-send.test.ts +4 -4
- package/src/__tests__/secret-routes-managed-proxy.test.ts +78 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +73 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +4 -4
- package/src/__tests__/skill-feature-flags.test.ts +11 -19
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
- package/src/__tests__/skill-load-inline-command.test.ts +3 -3
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-memory.test.ts +2 -4
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -4
- package/src/__tests__/skill-projection.benchmark.test.ts +1 -3
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +16 -2
- package/src/__tests__/slack-channel-config.test.ts +1 -1
- package/src/__tests__/slack-messaging-token-resolution.test.ts +22 -24
- package/src/__tests__/slack-share-routes.test.ts +5 -5
- package/src/__tests__/slack-skill.test.ts +5 -69
- package/src/__tests__/system-prompt.test.ts +39 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -1
- package/src/__tests__/workspace-migration-018-rekey-compound-credential-keys.test.ts +181 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +5 -4
- package/src/acp/client-handler.ts +113 -31
- package/src/acp/session-manager.ts +29 -27
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/cli/AGENTS.md +113 -0
- package/src/cli/commands/autonomy.ts +3 -5
- package/src/cli/commands/browser-relay.ts +2 -17
- package/src/cli/commands/contacts.ts +6 -4
- package/src/cli/commands/conversations.ts +13 -1
- package/src/cli/commands/credential-execution.ts +17 -3
- package/src/cli/commands/credentials.ts +2 -8
- package/src/cli/commands/memory.ts +2 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +706 -0
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +686 -0
- package/src/cli/commands/oauth/__tests__/mode.test.ts +625 -0
- package/src/cli/commands/oauth/__tests__/ping.test.ts +631 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +574 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +416 -0
- package/src/cli/commands/oauth/__tests__/status.test.ts +551 -0
- package/src/cli/commands/oauth/__tests__/token.test.ts +420 -0
- package/src/cli/commands/oauth/apps.ts +87 -50
- package/src/cli/commands/oauth/connect.ts +405 -0
- package/src/cli/commands/oauth/disconnect.ts +285 -0
- package/src/cli/commands/oauth/index.ts +62 -20
- package/src/cli/commands/oauth/mode.ts +251 -0
- package/src/cli/commands/oauth/ping.ts +196 -0
- package/src/cli/commands/oauth/providers.ts +589 -55
- package/src/cli/commands/oauth/request.ts +564 -0
- package/src/cli/commands/oauth/shared.ts +114 -0
- package/src/cli/commands/oauth/status.ts +191 -0
- package/src/cli/commands/oauth/token.ts +150 -0
- package/src/cli/commands/platform/connect.ts +104 -0
- package/src/cli/commands/platform/disconnect.ts +118 -0
- package/src/cli/commands/platform/index.ts +252 -0
- package/src/cli/commands/sequence.ts +5 -4
- package/src/cli/commands/shotgun.ts +16 -0
- package/src/cli/commands/skills.ts +173 -41
- package/src/cli/commands/usage.ts +5 -11
- package/src/cli/lib/daemon-credential-client.ts +22 -38
- package/src/cli/program.ts +1 -1
- package/src/cli.ts +82 -17
- package/src/config/assistant-feature-flags.ts +77 -18
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/conversations/SKILL.md +20 -0
- package/src/config/bundled-skills/conversations/TOOLS.json +23 -0
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +66 -0
- package/src/config/bundled-skills/gmail/SKILL.md +13 -13
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +3 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +2 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +2 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +10 -4
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +19 -42
- package/src/config/bundled-skills/messaging/TOOLS.json +9 -9
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +5 -6
- package/src/config/bundled-skills/notifications/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +2 -2
- package/src/config/bundled-skills/settings/SKILL.md +5 -3
- package/src/config/bundled-skills/settings/TOOLS.json +17 -0
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +50 -0
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +7 -0
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +6 -1
- package/src/config/bundled-skills/settings/tools/identity-avatar.ts +55 -0
- package/src/config/bundled-skills/skills-catalog/SKILL.md +3 -3
- package/src/config/bundled-skills/slack/SKILL.md +58 -44
- package/src/config/bundled-tool-registry.ts +7 -19
- package/src/config/env.ts +5 -1
- package/src/config/feature-flag-registry.json +58 -42
- package/src/config/loader.ts +4 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/security.ts +9 -1
- package/src/config/schemas/services.ts +1 -1
- package/src/config/skill-state.ts +1 -3
- package/src/config/skills.ts +2 -4
- package/src/credential-execution/client.ts +1 -1
- package/src/credential-execution/feature-gates.ts +9 -16
- package/src/credential-execution/process-manager.ts +12 -0
- package/src/daemon/config-watcher.ts +4 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +10 -0
- package/src/daemon/conversation-agent-loop.ts +51 -2
- package/src/daemon/conversation-error.ts +36 -6
- package/src/daemon/conversation-memory.ts +0 -1
- package/src/daemon/conversation-messaging.ts +9 -0
- package/src/daemon/conversation-runtime-assembly.ts +33 -0
- package/src/daemon/conversation-surfaces.ts +120 -14
- package/src/daemon/conversation.ts +5 -0
- package/src/daemon/handlers/config-slack-channel.ts +43 -1
- package/src/daemon/handlers/conversations.ts +41 -33
- package/src/daemon/handlers/skills.ts +148 -3
- package/src/daemon/host-bash-proxy.ts +16 -0
- package/src/daemon/host-cu-proxy.ts +16 -0
- package/src/daemon/host-file-proxy.ts +16 -0
- package/src/daemon/lifecycle.ts +73 -3
- package/src/daemon/message-types/acp.ts +0 -15
- package/src/daemon/message-types/conversations.ts +1 -0
- package/src/daemon/message-types/guardian-actions.ts +2 -0
- package/src/daemon/message-types/host-bash.ts +6 -1
- package/src/daemon/message-types/host-cu.ts +6 -1
- package/src/daemon/message-types/host-file.ts +6 -1
- package/src/daemon/message-types/integrations.ts +0 -1
- package/src/daemon/message-types/memory.ts +0 -1
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/schedules.ts +9 -0
- package/src/daemon/server.ts +48 -9
- package/src/email/feature-gate.ts +3 -3
- package/src/heartbeat/heartbeat-service.ts +48 -0
- package/src/hooks/cli.ts +74 -0
- package/src/inbound/platform-callback-registration.ts +68 -19
- package/src/mcp/client.ts +6 -1
- package/src/mcp/manager.ts +2 -1
- package/src/mcp/mcp-oauth-provider.ts +3 -3
- package/src/memory/app-store.ts +3 -3
- package/src/memory/conversation-crud.ts +213 -0
- package/src/memory/conversation-key-store.ts +26 -0
- package/src/memory/conversation-title-service.ts +7 -17
- package/src/memory/db-init.ts +24 -0
- package/src/memory/embedding-local.ts +47 -2
- package/src/memory/indexer.ts +13 -10
- package/src/memory/items-extractor.ts +12 -4
- package/src/memory/job-utils.ts +5 -0
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/journal-memory.ts +6 -2
- package/src/memory/llm-request-log-store.ts +88 -21
- package/src/memory/memory-recall-log-store.ts +128 -0
- package/src/memory/migrations/194-memory-recall-logs.ts +50 -0
- package/src/memory/migrations/195-oauth-providers-ping-config.ts +23 -0
- package/src/memory/migrations/196-messages-conversation-created-at-index.ts +9 -0
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +186 -0
- package/src/memory/migrations/197-oauth-providers-behavior-columns.ts +29 -0
- package/src/memory/migrations/198-drop-setup-skill-id-column.ts +11 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/retriever.test.ts +4 -5
- package/src/memory/schema/infrastructure.ts +31 -0
- package/src/memory/schema/oauth.ts +14 -0
- package/src/messaging/provider.ts +13 -12
- package/src/messaging/providers/gmail/adapter.ts +44 -35
- package/src/messaging/providers/slack/adapter.ts +63 -33
- package/src/messaging/providers/telegram-bot/adapter.ts +7 -9
- package/src/messaging/providers/whatsapp/adapter.ts +6 -8
- package/src/notifications/adapters/telegram.ts +78 -2
- package/src/oauth/__tests__/identity-verifier.test.ts +464 -0
- package/src/oauth/byo-connection.test.ts +22 -24
- package/src/oauth/connect-orchestrator.ts +79 -64
- package/src/oauth/connect-types.ts +7 -65
- package/src/oauth/connection-resolver.test.ts +13 -13
- package/src/oauth/connection-resolver.ts +3 -4
- package/src/oauth/identity-verifier.ts +177 -0
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +251 -5
- package/src/oauth/platform-connection.test.ts +56 -6
- package/src/oauth/platform-connection.ts +8 -1
- package/src/oauth/seed-providers.ts +256 -34
- package/src/permissions/checker.ts +129 -3
- package/src/permissions/trust-client.ts +2 -2
- package/src/platform/client.ts +2 -2
- package/src/prompts/journal-context.ts +6 -1
- package/src/prompts/system-prompt.ts +43 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -5
- package/src/providers/anthropic/client.ts +139 -28
- package/src/runtime/auth/__tests__/middleware.test.ts +19 -0
- package/src/runtime/auth/route-policy.ts +0 -1
- package/src/runtime/btw-sidechain.ts +7 -1
- package/src/runtime/channel-approvals.ts +2 -2
- package/src/runtime/channel-readiness-service.ts +30 -7
- package/src/runtime/guardian-action-service.ts +7 -2
- package/src/runtime/http-router.ts +31 -0
- package/src/runtime/http-server.ts +26 -7
- package/src/runtime/http-types.ts +9 -0
- package/src/runtime/pending-interactions.ts +21 -3
- package/src/runtime/routes/acp-routes.ts +46 -28
- package/src/runtime/routes/app-management-routes.ts +123 -0
- package/src/runtime/routes/app-routes.ts +31 -0
- package/src/runtime/routes/approval-routes.ts +108 -3
- package/src/runtime/routes/attachment-routes.ts +45 -0
- package/src/runtime/routes/avatar-routes.ts +16 -0
- package/src/runtime/routes/brain-graph-routes.ts +18 -0
- package/src/runtime/routes/btw-routes.ts +20 -0
- package/src/runtime/routes/call-routes.ts +81 -0
- package/src/runtime/routes/channel-readiness-routes.ts +48 -7
- package/src/runtime/routes/channel-routes.ts +18 -0
- package/src/runtime/routes/channel-verification-routes.ts +49 -1
- package/src/runtime/routes/contact-routes.ts +77 -0
- package/src/runtime/routes/conversation-attention-routes.ts +37 -0
- package/src/runtime/routes/conversation-management-routes.ts +125 -0
- package/src/runtime/routes/conversation-query-routes.ts +78 -0
- package/src/runtime/routes/conversation-routes.ts +191 -39
- package/src/runtime/routes/conversation-starter-routes.ts +29 -0
- package/src/runtime/routes/debug-routes.ts +23 -0
- package/src/runtime/routes/diagnostics-routes.ts +30 -0
- package/src/runtime/routes/documents-routes.ts +42 -0
- package/src/runtime/routes/events-routes.ts +10 -0
- package/src/runtime/routes/global-search-routes.ts +35 -0
- package/src/runtime/routes/guardian-action-routes.ts +61 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +77 -2
- package/src/runtime/routes/heartbeat-routes.ts +278 -0
- package/src/runtime/routes/host-bash-routes.ts +16 -1
- package/src/runtime/routes/host-cu-routes.ts +23 -1
- package/src/runtime/routes/host-file-routes.ts +18 -1
- package/src/runtime/routes/identity-routes.ts +35 -0
- package/src/runtime/routes/inbound-message-handler.ts +46 -25
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -8
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +30 -2
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -2
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/integrations/twilio.ts +32 -22
- package/src/runtime/routes/invite-routes.ts +83 -0
- package/src/runtime/routes/log-export-routes.ts +14 -0
- package/src/runtime/routes/memory-item-routes.ts +99 -1
- package/src/runtime/routes/migration-rollback-routes.ts +25 -0
- package/src/runtime/routes/migration-routes.ts +40 -0
- package/src/runtime/routes/notification-routes.ts +20 -0
- package/src/runtime/routes/oauth-apps.ts +13 -4
- package/src/runtime/routes/pairing-routes.ts +15 -0
- package/src/runtime/routes/recording-routes.ts +72 -0
- package/src/runtime/routes/schedule-routes.ts +77 -5
- package/src/runtime/routes/secret-routes.ts +99 -14
- package/src/runtime/routes/settings-routes.ts +102 -19
- package/src/runtime/routes/skills-routes.ts +141 -18
- package/src/runtime/routes/subagents-routes.ts +38 -3
- package/src/runtime/routes/surface-action-routes.ts +66 -24
- package/src/runtime/routes/surface-content-routes.ts +20 -0
- package/src/runtime/routes/telemetry-routes.ts +12 -0
- package/src/runtime/routes/trace-event-routes.ts +25 -0
- package/src/runtime/routes/trust-rules-routes.ts +46 -0
- package/src/runtime/routes/tts-routes.ts +15 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +38 -0
- package/src/runtime/routes/usage-routes.ts +59 -0
- package/src/runtime/routes/watch-routes.ts +28 -0
- package/src/runtime/routes/work-items-routes.ts +59 -0
- package/src/runtime/routes/workspace-commit-routes.ts +12 -0
- package/src/runtime/routes/workspace-routes.ts +102 -0
- package/src/schedule/integration-status.ts +2 -2
- package/src/schedule/scheduler.ts +7 -1
- package/src/security/AGENTS.md +7 -0
- package/src/security/ces-rpc-credential-backend.ts +19 -16
- package/src/security/credential-backend.ts +1 -1
- package/src/security/encrypted-store.ts +3 -3
- package/src/security/oauth-completion-page.ts +153 -0
- package/src/security/oauth2.ts +58 -17
- package/src/security/secret-ingress.ts +174 -0
- package/src/security/secret-patterns.ts +133 -0
- package/src/security/secret-scanner.ts +28 -117
- package/src/security/secure-keys.ts +207 -7
- package/src/security/token-manager.ts +3 -6
- package/src/signals/bash.ts +6 -1
- package/src/signals/confirm.ts +12 -8
- package/src/signals/user-message.ts +18 -3
- package/src/skills/catalog-cache.ts +44 -0
- package/src/skills/catalog-search.ts +18 -0
- package/src/skills/skill-memory.ts +1 -2
- package/src/tasks/task-runner.ts +7 -1
- package/src/tools/credentials/broker.ts +1 -1
- package/src/tools/credentials/metadata-store.ts +1 -1
- package/src/tools/credentials/post-connect-hooks.ts +1 -1
- package/src/tools/credentials/vault.ts +36 -48
- package/src/tools/host-terminal/host-shell.ts +16 -3
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/definitions.ts +1 -1
- package/src/tools/memory/handlers.test.ts +2 -4
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/skills/sandbox-runner.ts +16 -3
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/terminal/shell.ts +16 -3
- package/src/tools/tool-manifest.ts +1 -1
- package/src/util/log-redact.ts +9 -34
- package/src/util/logger.ts +11 -1
- package/src/util/sentry-log-stream.ts +51 -0
- package/src/watcher/providers/github.ts +2 -2
- package/src/watcher/providers/gmail.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +1 -1
- package/src/watcher/providers/linear.ts +2 -2
- package/src/workspace/migrations/011-backfill-installation-id.ts +5 -3
- package/src/workspace/migrations/020-rename-oauth-skill-dirs.ts +119 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/docs/architecture/keychain-broker.md +0 -68
- package/src/cli/commands/oauth/connections.ts +0 -734
- package/src/cli/commands/oauth/platform.ts +0 -525
- package/src/cli/commands/platform.ts +0 -176
- package/src/config/bundled-skills/slack/TOOLS.json +0 -272
- package/src/config/bundled-skills/slack/tools/shared.ts +0 -34
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +0 -27
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +0 -38
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +0 -146
- package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +0 -105
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +0 -26
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +0 -27
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +0 -25
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +0 -372
- package/src/oauth/provider-behaviors.ts +0 -634
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "../../channels/types.js";
|
|
14
14
|
import { touchContactInteraction } from "../../contacts/contacts-write.js";
|
|
15
15
|
import type { TrustContext } from "../../daemon/conversation-runtime-assembly.js";
|
|
16
|
+
import type { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
16
17
|
import * as attachmentsStore from "../../memory/attachments-store.js";
|
|
17
18
|
import {
|
|
18
19
|
recordConversationSeenSignal,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
} from "../../memory/conversation-attention-store.js";
|
|
21
22
|
import * as deliveryChannels from "../../memory/delivery-channels.js";
|
|
22
23
|
import * as deliveryCrud from "../../memory/delivery-crud.js";
|
|
24
|
+
import * as deliveryStatus from "../../memory/delivery-status.js";
|
|
23
25
|
import * as externalConversationStore from "../../memory/external-conversation-store.js";
|
|
24
26
|
import { canonicalizeInboundIdentity } from "../../util/canonicalize-identity.js";
|
|
25
27
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -57,6 +59,7 @@ export async function handleChannelInbound(
|
|
|
57
59
|
approvalConversationGenerator?: ApprovalConversationGenerator,
|
|
58
60
|
_guardianActionCopyGenerator?: GuardianActionCopyGenerator,
|
|
59
61
|
_guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator,
|
|
62
|
+
heartbeatService?: HeartbeatService,
|
|
60
63
|
): Promise<Response> {
|
|
61
64
|
// Gateway-origin proof is enforced by route-policy middleware (svc_gateway
|
|
62
65
|
// principal type required) before this handler runs. The exchange JWT
|
|
@@ -641,7 +644,7 @@ export async function handleChannelInbound(
|
|
|
641
644
|
// For new (non-duplicate) messages, run the secret ingress check
|
|
642
645
|
// synchronously, then fire off the agent loop in the background.
|
|
643
646
|
if (!result.duplicate && processMessage) {
|
|
644
|
-
runSecretIngressCheck({
|
|
647
|
+
const ingressResult = runSecretIngressCheck({
|
|
645
648
|
eventId: result.eventId,
|
|
646
649
|
sourceChannel,
|
|
647
650
|
conversationExternalId,
|
|
@@ -659,30 +662,48 @@ export async function handleChannelInbound(
|
|
|
659
662
|
canonicalAssistantId,
|
|
660
663
|
});
|
|
661
664
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
trustCtx
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
665
|
+
if (ingressResult.blocked) {
|
|
666
|
+
// Intentional block — mark the event as processed (not failed/dead-lettered).
|
|
667
|
+
deliveryStatus.markProcessed(result.eventId);
|
|
668
|
+
log.info(
|
|
669
|
+
{
|
|
670
|
+
eventId: result.eventId,
|
|
671
|
+
detectedTypes: ingressResult.detectedTypes,
|
|
672
|
+
},
|
|
673
|
+
"Channel message blocked at ingress: contains secrets",
|
|
674
|
+
);
|
|
675
|
+
} else {
|
|
676
|
+
// Guardian messages reset the heartbeat timer so the next heartbeat
|
|
677
|
+
// fires a full interval after this interaction.
|
|
678
|
+
if (trustCtx.trustClass === "guardian") {
|
|
679
|
+
heartbeatService?.resetTimer();
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Fire-and-forget: process the message and deliver the reply in the background.
|
|
683
|
+
// The HTTP response returns immediately so the gateway webhook is not blocked.
|
|
684
|
+
// The onEvent callback in processMessage registers pending interactions, and
|
|
685
|
+
// approval interception (above) handles decisions via the pending-interactions tracker.
|
|
686
|
+
processChannelMessageInBackground({
|
|
687
|
+
processMessage,
|
|
688
|
+
conversationId: result.conversationId,
|
|
689
|
+
eventId: result.eventId,
|
|
690
|
+
content: trimmedContent,
|
|
691
|
+
attachmentIds: hasAttachments ? attachmentIds : undefined,
|
|
692
|
+
sourceChannel,
|
|
693
|
+
sourceInterface,
|
|
694
|
+
externalChatId: conversationExternalId,
|
|
695
|
+
trustCtx,
|
|
696
|
+
metadataHints,
|
|
697
|
+
metadataUxBrief,
|
|
698
|
+
commandIntent,
|
|
699
|
+
sourceLanguageCode,
|
|
700
|
+
replyCallbackUrl,
|
|
701
|
+
mintBearerToken,
|
|
702
|
+
assistantId: canonicalAssistantId,
|
|
703
|
+
approvalCopyGenerator,
|
|
704
|
+
chatType: sourceChatType,
|
|
705
|
+
});
|
|
706
|
+
}
|
|
686
707
|
}
|
|
687
708
|
|
|
688
709
|
return Response.json({
|
|
@@ -447,10 +447,11 @@ export async function enforceIngressAcl(
|
|
|
447
447
|
);
|
|
448
448
|
}
|
|
449
449
|
|
|
450
|
+
const replyText = guardianNotified
|
|
451
|
+
? `Hmm looks like you don't have access to talk to me. I'll let ${resolveGuardianLabel(sourceChannel, canonicalAssistantId)} know you tried talking to me and get back to you.`
|
|
452
|
+
: "Sorry, you haven't been approved to message this assistant.";
|
|
453
|
+
let replyDelivered = false;
|
|
450
454
|
if (replyCallbackUrl) {
|
|
451
|
-
const replyText = guardianNotified
|
|
452
|
-
? `Hmm looks like you don't have access to talk to me. I'll let ${resolveGuardianLabel(sourceChannel, canonicalAssistantId)} know you tried talking to me and get back to you.`
|
|
453
|
-
: "Sorry, you haven't been approved to message this assistant.";
|
|
454
455
|
const replyPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
455
456
|
chatId: conversationExternalId,
|
|
456
457
|
text: replyText,
|
|
@@ -467,6 +468,7 @@ export async function enforceIngressAcl(
|
|
|
467
468
|
replyPayload,
|
|
468
469
|
mintBearerToken(),
|
|
469
470
|
);
|
|
471
|
+
replyDelivered = true;
|
|
470
472
|
} catch (err) {
|
|
471
473
|
log.error(
|
|
472
474
|
{ err, conversationExternalId },
|
|
@@ -481,6 +483,9 @@ export async function enforceIngressAcl(
|
|
|
481
483
|
accepted: true,
|
|
482
484
|
denied: true,
|
|
483
485
|
reason: "not_a_member",
|
|
486
|
+
// Include reply text so the gateway can deliver directly when
|
|
487
|
+
// callback delivery failed (e.g. signing-key mismatch → 401).
|
|
488
|
+
...(!replyDelivered && { replyText }),
|
|
484
489
|
}),
|
|
485
490
|
guardianVerifyCode,
|
|
486
491
|
};
|
|
@@ -714,15 +719,16 @@ export async function enforceIngressAcl(
|
|
|
714
719
|
}
|
|
715
720
|
}
|
|
716
721
|
|
|
722
|
+
const inactiveReplyText = guardianNotified
|
|
723
|
+
? `Hmm looks like you don't have access to talk to me. I'll let ${resolveGuardianLabel(sourceChannel, canonicalAssistantId)} know you tried talking to me and get back to you.`
|
|
724
|
+
: "Sorry, you haven't been approved to message this assistant.";
|
|
725
|
+
let inactiveReplyDelivered = false;
|
|
717
726
|
if (replyCallbackUrl) {
|
|
718
|
-
const replyText = guardianNotified
|
|
719
|
-
? `Hmm looks like you don't have access to talk to me. I'll let ${resolveGuardianLabel(sourceChannel, canonicalAssistantId)} know you tried talking to me and get back to you.`
|
|
720
|
-
: "Sorry, you haven't been approved to message this assistant.";
|
|
721
727
|
const inactiveReplyPayload: Parameters<
|
|
722
728
|
typeof deliverChannelReply
|
|
723
729
|
>[1] = {
|
|
724
730
|
chatId: conversationExternalId,
|
|
725
|
-
text:
|
|
731
|
+
text: inactiveReplyText,
|
|
726
732
|
assistantId,
|
|
727
733
|
};
|
|
728
734
|
// On Slack, send as ephemeral so only the requester sees the rejection
|
|
@@ -739,6 +745,7 @@ export async function enforceIngressAcl(
|
|
|
739
745
|
inactiveReplyPayload,
|
|
740
746
|
mintBearerToken(),
|
|
741
747
|
);
|
|
748
|
+
inactiveReplyDelivered = true;
|
|
742
749
|
} catch (err) {
|
|
743
750
|
log.error(
|
|
744
751
|
{ err, conversationExternalId },
|
|
@@ -752,6 +759,7 @@ export async function enforceIngressAcl(
|
|
|
752
759
|
accepted: true,
|
|
753
760
|
denied: true,
|
|
754
761
|
reason: `member_${channelStatusToMemberStatus(resolvedMember.channel.status)}`,
|
|
762
|
+
...(!inactiveReplyDelivered && { replyText: inactiveReplyText }),
|
|
755
763
|
}),
|
|
756
764
|
guardianVerifyCode,
|
|
757
765
|
};
|
|
@@ -763,10 +771,13 @@ export async function enforceIngressAcl(
|
|
|
763
771
|
{ sourceChannel, channelId: resolvedMember.channel.id },
|
|
764
772
|
"Ingress ACL: member policy deny",
|
|
765
773
|
);
|
|
774
|
+
const denyReplyText =
|
|
775
|
+
"Sorry, you haven't been approved to message this assistant.";
|
|
776
|
+
let denyReplyDelivered = false;
|
|
766
777
|
if (replyCallbackUrl) {
|
|
767
778
|
const denyPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
768
779
|
chatId: conversationExternalId,
|
|
769
|
-
text:
|
|
780
|
+
text: denyReplyText,
|
|
770
781
|
assistantId,
|
|
771
782
|
};
|
|
772
783
|
if (sourceChannel === "slack" && (canonicalSenderId ?? rawSenderId)) {
|
|
@@ -779,6 +790,7 @@ export async function enforceIngressAcl(
|
|
|
779
790
|
denyPayload,
|
|
780
791
|
mintBearerToken(),
|
|
781
792
|
);
|
|
793
|
+
denyReplyDelivered = true;
|
|
782
794
|
} catch (err) {
|
|
783
795
|
log.error(
|
|
784
796
|
{ err, conversationExternalId },
|
|
@@ -792,6 +804,7 @@ export async function enforceIngressAcl(
|
|
|
792
804
|
accepted: true,
|
|
793
805
|
denied: true,
|
|
794
806
|
reason: "policy_deny",
|
|
807
|
+
...(!denyReplyDelivered && { replyText: denyReplyText }),
|
|
795
808
|
}),
|
|
796
809
|
guardianVerifyCode,
|
|
797
810
|
};
|
|
@@ -9,6 +9,7 @@ import type { ChannelId } from "../../../channels/types.js";
|
|
|
9
9
|
import type { TrustContext } from "../../../daemon/conversation-runtime-assembly.js";
|
|
10
10
|
import { recordConversationSeenSignal } from "../../../memory/conversation-attention-store.js";
|
|
11
11
|
import * as deliveryCrud from "../../../memory/delivery-crud.js";
|
|
12
|
+
import { checkIngressForSecrets } from "../../../security/secret-ingress.js";
|
|
12
13
|
import { getLogger } from "../../../util/logger.js";
|
|
13
14
|
|
|
14
15
|
const log = getLogger("runtime-http");
|
|
@@ -35,10 +36,21 @@ export interface SecretIngressCheckParams {
|
|
|
35
36
|
canonicalAssistantId: string;
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
export interface SecretIngressCheckResult {
|
|
40
|
+
blocked: boolean;
|
|
41
|
+
detectedTypes?: string[];
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
/**
|
|
39
|
-
* Persist the raw payload and record a Telegram seen signal.
|
|
45
|
+
* Persist the raw payload, scan for secrets, and record a Telegram seen signal.
|
|
46
|
+
*
|
|
47
|
+
* Returns `{ blocked: true, detectedTypes }` when the message contains
|
|
48
|
+
* known-format secrets — the caller should skip background dispatch and mark
|
|
49
|
+
* the event as processed (not failed/dead-lettered).
|
|
40
50
|
*/
|
|
41
|
-
export function runSecretIngressCheck(
|
|
51
|
+
export function runSecretIngressCheck(
|
|
52
|
+
params: SecretIngressCheckParams,
|
|
53
|
+
): SecretIngressCheckResult {
|
|
42
54
|
const {
|
|
43
55
|
eventId,
|
|
44
56
|
sourceChannel,
|
|
@@ -73,6 +85,20 @@ export function runSecretIngressCheck(params: SecretIngressCheckParams): void {
|
|
|
73
85
|
assistantId: canonicalAssistantId,
|
|
74
86
|
});
|
|
75
87
|
|
|
88
|
+
// ── Secret ingress scan ──
|
|
89
|
+
// Scan trimmedContent (post-transcription) so secrets introduced via
|
|
90
|
+
// transcribed audio are also caught.
|
|
91
|
+
const ingressResult = checkIngressForSecrets(trimmedContent);
|
|
92
|
+
if (ingressResult.blocked) {
|
|
93
|
+
// Clear stored payload to prevent secret-bearing content on disk.
|
|
94
|
+
deliveryCrud.clearPayload(eventId);
|
|
95
|
+
log.warn(
|
|
96
|
+
{ eventId, detectedTypes: ingressResult.detectedTypes },
|
|
97
|
+
"Channel message blocked at ingress: secret detected",
|
|
98
|
+
);
|
|
99
|
+
return { blocked: true, detectedTypes: ingressResult.detectedTypes };
|
|
100
|
+
}
|
|
101
|
+
|
|
76
102
|
// Record inferred seen signal for non-duplicate Telegram inbound messages
|
|
77
103
|
if (sourceChannel === "telegram") {
|
|
78
104
|
try {
|
|
@@ -99,4 +125,6 @@ export function runSecretIngressCheck(params: SecretIngressCheckParams): void {
|
|
|
99
125
|
);
|
|
100
126
|
}
|
|
101
127
|
}
|
|
128
|
+
|
|
129
|
+
return { blocked: false };
|
|
102
130
|
}
|
|
@@ -15,8 +15,7 @@ import { getLogger } from "../../../util/logger.js";
|
|
|
15
15
|
|
|
16
16
|
const log = getLogger("transcribe-audio");
|
|
17
17
|
|
|
18
|
-
const VOICE_TRANSCRIPTION_FLAG_KEY =
|
|
19
|
-
"feature_flags.channel-voice-transcription.enabled" as const;
|
|
18
|
+
const VOICE_TRANSCRIPTION_FLAG_KEY = "channel-voice-transcription" as const;
|
|
20
19
|
|
|
21
20
|
/** Timeout for the entire transcription pipeline (all attachments). */
|
|
22
21
|
const TRANSCRIPTION_TIMEOUT_MS = 30_000;
|
|
@@ -28,7 +28,7 @@ const log = getLogger("slack-share");
|
|
|
28
28
|
* Resolve the Slack bot token from the OAuth connection store.
|
|
29
29
|
*/
|
|
30
30
|
async function resolveSlackToken(): Promise<string | undefined> {
|
|
31
|
-
const conn = getConnectionByProvider("
|
|
31
|
+
const conn = getConnectionByProvider("slack");
|
|
32
32
|
return conn
|
|
33
33
|
? await getSecureKeyAsync(`oauth_connection/${conn.id}/access_token`)
|
|
34
34
|
: undefined;
|
|
@@ -271,17 +271,22 @@ export async function handleProvisionTwilioNumber(
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
let body: { country?: string; areaCode?: string };
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
274
|
+
const provisionText = await req.text();
|
|
275
|
+
if (!provisionText.trim()) {
|
|
276
|
+
body = {};
|
|
277
|
+
} else {
|
|
278
|
+
try {
|
|
279
|
+
body = JSON.parse(provisionText) as typeof body;
|
|
280
|
+
} catch {
|
|
281
|
+
return Response.json(
|
|
282
|
+
{
|
|
283
|
+
success: false,
|
|
284
|
+
hasCredentials: await hasTwilioCredentials(),
|
|
285
|
+
error: "Invalid JSON in request body",
|
|
286
|
+
},
|
|
287
|
+
{ status: 400 },
|
|
288
|
+
);
|
|
289
|
+
}
|
|
285
290
|
}
|
|
286
291
|
const { accountSid, authToken } = await getTwilioCredentials();
|
|
287
292
|
const country = body.country ?? "US";
|
|
@@ -406,17 +411,22 @@ export async function handleReleaseTwilioNumber(
|
|
|
406
411
|
}
|
|
407
412
|
|
|
408
413
|
let body: { phoneNumber?: string };
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
414
|
+
const releaseText = await req.text();
|
|
415
|
+
if (!releaseText.trim()) {
|
|
416
|
+
body = {};
|
|
417
|
+
} else {
|
|
418
|
+
try {
|
|
419
|
+
body = JSON.parse(releaseText) as typeof body;
|
|
420
|
+
} catch {
|
|
421
|
+
return Response.json(
|
|
422
|
+
{
|
|
423
|
+
success: false,
|
|
424
|
+
hasCredentials: await hasTwilioCredentials(),
|
|
425
|
+
error: "Invalid JSON in request body",
|
|
426
|
+
},
|
|
427
|
+
{ status: 400 },
|
|
428
|
+
);
|
|
429
|
+
}
|
|
420
430
|
}
|
|
421
431
|
const raw = loadRawConfig();
|
|
422
432
|
const twilio = (raw?.twilio ?? {}) as Record<string, unknown>;
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* POST /v1/contacts/invites/:id/call — trigger an outbound call for a phone invite
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
12
14
|
import type { RouteDefinition } from "../http-router.js";
|
|
13
15
|
import {
|
|
14
16
|
createIngressInvite,
|
|
@@ -169,28 +171,109 @@ export function inviteRouteDefinitions(): RouteDefinition[] {
|
|
|
169
171
|
{
|
|
170
172
|
endpoint: "contacts/invites",
|
|
171
173
|
method: "GET",
|
|
174
|
+
summary: "List invites",
|
|
175
|
+
description:
|
|
176
|
+
"Return all invites, optionally filtered by sourceChannel or status.",
|
|
177
|
+
tags: ["contacts"],
|
|
178
|
+
queryParams: [
|
|
179
|
+
{
|
|
180
|
+
name: "sourceChannel",
|
|
181
|
+
schema: { type: "string" },
|
|
182
|
+
description: "Filter by source channel",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "status",
|
|
186
|
+
schema: { type: "string" },
|
|
187
|
+
description: "Filter by invite status",
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
responseBody: z.object({
|
|
191
|
+
ok: z.boolean(),
|
|
192
|
+
invites: z.array(z.unknown()).describe("Invite objects"),
|
|
193
|
+
}),
|
|
172
194
|
handler: ({ url }) => handleListInvites(url),
|
|
173
195
|
},
|
|
174
196
|
{
|
|
175
197
|
endpoint: "contacts/invites",
|
|
176
198
|
method: "POST",
|
|
199
|
+
summary: "Create an invite",
|
|
200
|
+
description:
|
|
201
|
+
'Create a new invite. Supports voice invites when sourceChannel is "phone".',
|
|
202
|
+
tags: ["contacts"],
|
|
203
|
+
requestBody: z.object({
|
|
204
|
+
contactId: z.string().describe("Contact to invite"),
|
|
205
|
+
sourceChannel: z
|
|
206
|
+
.string()
|
|
207
|
+
.describe("Source channel (e.g. phone)")
|
|
208
|
+
.optional(),
|
|
209
|
+
note: z.string().describe("Optional note").optional(),
|
|
210
|
+
maxUses: z.number().describe("Max redemptions").optional(),
|
|
211
|
+
expiresInMs: z.number().describe("Expiry duration in ms").optional(),
|
|
212
|
+
contactName: z.string().describe("Contact display name").optional(),
|
|
213
|
+
expectedExternalUserId: z
|
|
214
|
+
.string()
|
|
215
|
+
.describe("Expected user ID (E.164 for phone)")
|
|
216
|
+
.optional(),
|
|
217
|
+
friendName: z
|
|
218
|
+
.string()
|
|
219
|
+
.describe("Friend name for the invite")
|
|
220
|
+
.optional(),
|
|
221
|
+
guardianName: z.string().describe("Guardian name").optional(),
|
|
222
|
+
}),
|
|
223
|
+
responseBody: z.object({
|
|
224
|
+
ok: z.boolean(),
|
|
225
|
+
invite: z.object({}).passthrough().describe("Created invite"),
|
|
226
|
+
}),
|
|
177
227
|
handler: async ({ req }) => handleCreateInvite(req),
|
|
178
228
|
},
|
|
179
229
|
{
|
|
180
230
|
endpoint: "contacts/invites/redeem",
|
|
181
231
|
method: "POST",
|
|
232
|
+
summary: "Redeem an invite",
|
|
233
|
+
description: "Redeem an invite by token or voice code.",
|
|
234
|
+
tags: ["contacts"],
|
|
235
|
+
requestBody: z.object({
|
|
236
|
+
token: z.string().describe("Invite token (token-based redemption)"),
|
|
237
|
+
code: z.string().describe("Voice code (voice-code redemption)"),
|
|
238
|
+
callerExternalUserId: z
|
|
239
|
+
.string()
|
|
240
|
+
.describe("Caller E.164 phone (voice-code)"),
|
|
241
|
+
externalUserId: z.string().describe("External user ID (token-based)"),
|
|
242
|
+
externalChatId: z.string().describe("External chat ID (token-based)"),
|
|
243
|
+
sourceChannel: z.string().describe("Source channel (token-based)"),
|
|
244
|
+
assistantId: z.string().describe("Assistant ID (voice-code)"),
|
|
245
|
+
}),
|
|
246
|
+
responseBody: z.object({
|
|
247
|
+
ok: z.boolean(),
|
|
248
|
+
invite: z
|
|
249
|
+
.object({})
|
|
250
|
+
.passthrough()
|
|
251
|
+
.describe("Redeemed invite (token path)"),
|
|
252
|
+
type: z.string().describe("Redemption type (voice path)"),
|
|
253
|
+
memberId: z.string().describe("Member ID (voice path)"),
|
|
254
|
+
}),
|
|
182
255
|
handler: async ({ req }) => handleRedeemInvite(req),
|
|
183
256
|
},
|
|
184
257
|
{
|
|
185
258
|
endpoint: "contacts/invites/:id",
|
|
186
259
|
method: "DELETE",
|
|
187
260
|
policyKey: "contacts/invites",
|
|
261
|
+
summary: "Revoke an invite",
|
|
262
|
+
description: "Revoke an invite by ID.",
|
|
263
|
+
tags: ["contacts"],
|
|
188
264
|
handler: ({ params }) => handleRevokeInvite(params.id),
|
|
189
265
|
},
|
|
190
266
|
{
|
|
191
267
|
endpoint: "contacts/invites/:id/call",
|
|
192
268
|
method: "POST",
|
|
193
269
|
policyKey: "contacts/invites",
|
|
270
|
+
summary: "Trigger invite call",
|
|
271
|
+
description: "Trigger an outbound call for a phone invite.",
|
|
272
|
+
tags: ["contacts"],
|
|
273
|
+
responseBody: z.object({
|
|
274
|
+
ok: z.boolean(),
|
|
275
|
+
callSid: z.string().describe("Call SID from the provider"),
|
|
276
|
+
}),
|
|
194
277
|
handler: async ({ params }) => handleTriggerInviteCall(params.id),
|
|
195
278
|
},
|
|
196
279
|
];
|
|
@@ -22,6 +22,7 @@ import { tmpdir } from "node:os";
|
|
|
22
22
|
import { join, relative } from "node:path";
|
|
23
23
|
|
|
24
24
|
import { and, desc, eq, gte, lte } from "drizzle-orm";
|
|
25
|
+
import { z } from "zod";
|
|
25
26
|
|
|
26
27
|
import { getDb } from "../../memory/db.js";
|
|
27
28
|
import {
|
|
@@ -670,6 +671,19 @@ export function logExportRouteDefinitions(): RouteDefinition[] {
|
|
|
670
671
|
endpoint: "export",
|
|
671
672
|
method: "POST",
|
|
672
673
|
policyKey: "export",
|
|
674
|
+
summary: "Export logs and audit data",
|
|
675
|
+
description:
|
|
676
|
+
"Export audit records, daemon logs, workspace contents, and config as a tar.gz archive.",
|
|
677
|
+
tags: ["export"],
|
|
678
|
+
requestBody: z.object({
|
|
679
|
+
auditLimit: z
|
|
680
|
+
.number()
|
|
681
|
+
.int()
|
|
682
|
+
.describe("Max audit records (default 1000)"),
|
|
683
|
+
conversationId: z.string().describe("Scope to a single conversation"),
|
|
684
|
+
startTime: z.number().describe("Lower bound epoch ms"),
|
|
685
|
+
endTime: z.number().describe("Upper bound epoch ms"),
|
|
686
|
+
}),
|
|
673
687
|
handler: async ({ req }) => {
|
|
674
688
|
const body = (await req.json()) as ExportRequestBody;
|
|
675
689
|
return handleExport(body);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { and, asc, count, desc, eq, inArray, like, ne, or } from "drizzle-orm";
|
|
12
12
|
import { v4 as uuid } from "uuid";
|
|
13
|
+
import { z } from "zod";
|
|
13
14
|
|
|
14
15
|
import { getConfig } from "../../config/loader.js";
|
|
15
16
|
import { getDb } from "../../memory/db.js";
|
|
@@ -597,7 +598,11 @@ export async function handleUpdateMemoryItem(
|
|
|
597
598
|
// If sourceType was set (either directly or via mapping), also write verificationState
|
|
598
599
|
if (body.sourceType !== undefined && body.verificationState === undefined) {
|
|
599
600
|
set.verificationState =
|
|
600
|
-
body.sourceType === "tool"
|
|
601
|
+
body.sourceType === "tool"
|
|
602
|
+
? "user_confirmed"
|
|
603
|
+
: existing.verificationState === "user_reported"
|
|
604
|
+
? "user_reported"
|
|
605
|
+
: "assistant_inferred";
|
|
601
606
|
}
|
|
602
607
|
|
|
603
608
|
// If subject, statement, or kind changed, recompute fingerprint
|
|
@@ -717,29 +722,122 @@ export function memoryItemRouteDefinitions(): RouteDefinition[] {
|
|
|
717
722
|
{
|
|
718
723
|
endpoint: "memory-items",
|
|
719
724
|
method: "GET",
|
|
725
|
+
summary: "List memory items",
|
|
726
|
+
description:
|
|
727
|
+
"Return memory items with filtering, search, sorting, and pagination.",
|
|
728
|
+
tags: ["memory"],
|
|
729
|
+
queryParams: [
|
|
730
|
+
{
|
|
731
|
+
name: "kind",
|
|
732
|
+
schema: { type: "string" },
|
|
733
|
+
description: "Filter by kind",
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
name: "status",
|
|
737
|
+
schema: { type: "string" },
|
|
738
|
+
description: "Filter by status (default active)",
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
name: "search",
|
|
742
|
+
schema: { type: "string" },
|
|
743
|
+
description: "Full-text search query",
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
name: "sort",
|
|
747
|
+
schema: { type: "string" },
|
|
748
|
+
description: "Sort field (default lastSeenAt)",
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
name: "order",
|
|
752
|
+
schema: { type: "string" },
|
|
753
|
+
description: "asc or desc (default desc)",
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
name: "limit",
|
|
757
|
+
schema: { type: "integer" },
|
|
758
|
+
description: "Max results (default 100)",
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
name: "offset",
|
|
762
|
+
schema: { type: "integer" },
|
|
763
|
+
description: "Pagination offset",
|
|
764
|
+
},
|
|
765
|
+
],
|
|
766
|
+
responseBody: z.object({
|
|
767
|
+
items: z.array(z.unknown()).describe("Memory item objects"),
|
|
768
|
+
total: z.number(),
|
|
769
|
+
}),
|
|
720
770
|
handler: (ctx) => handleListMemoryItems(ctx.url),
|
|
721
771
|
},
|
|
722
772
|
{
|
|
723
773
|
endpoint: "memory-items/:id",
|
|
724
774
|
method: "GET",
|
|
725
775
|
policyKey: "memory-items",
|
|
776
|
+
summary: "Get a memory item",
|
|
777
|
+
description:
|
|
778
|
+
"Return a single memory item by ID with supersession metadata.",
|
|
779
|
+
tags: ["memory"],
|
|
780
|
+
responseBody: z.object({
|
|
781
|
+
item: z
|
|
782
|
+
.object({})
|
|
783
|
+
.passthrough()
|
|
784
|
+
.describe("Memory item with scopeLabel and supersession info"),
|
|
785
|
+
}),
|
|
726
786
|
handler: (ctx) => handleGetMemoryItem(ctx),
|
|
727
787
|
},
|
|
728
788
|
{
|
|
729
789
|
endpoint: "memory-items",
|
|
730
790
|
method: "POST",
|
|
791
|
+
summary: "Create a memory item",
|
|
792
|
+
description: "Create a new memory item and enqueue embedding.",
|
|
793
|
+
tags: ["memory"],
|
|
794
|
+
requestBody: z.object({
|
|
795
|
+
kind: z
|
|
796
|
+
.string()
|
|
797
|
+
.describe("Memory kind (identity, preference, project, etc.)"),
|
|
798
|
+
subject: z.string().describe("Subject line"),
|
|
799
|
+
statement: z.string().describe("Statement content"),
|
|
800
|
+
importance: z
|
|
801
|
+
.number()
|
|
802
|
+
.describe("Importance score (default 0.8)")
|
|
803
|
+
.optional(),
|
|
804
|
+
}),
|
|
805
|
+
responseBody: z.object({
|
|
806
|
+
item: z.object({}).passthrough().describe("Created memory item"),
|
|
807
|
+
}),
|
|
731
808
|
handler: (ctx) => handleCreateMemoryItem(ctx),
|
|
732
809
|
},
|
|
733
810
|
{
|
|
734
811
|
endpoint: "memory-items/:id",
|
|
735
812
|
method: "PATCH",
|
|
736
813
|
policyKey: "memory-items",
|
|
814
|
+
summary: "Update a memory item",
|
|
815
|
+
description: "Partially update fields on an existing memory item.",
|
|
816
|
+
tags: ["memory"],
|
|
817
|
+
requestBody: z.object({
|
|
818
|
+
subject: z.string(),
|
|
819
|
+
statement: z.string(),
|
|
820
|
+
kind: z.string(),
|
|
821
|
+
status: z.string(),
|
|
822
|
+
importance: z.number(),
|
|
823
|
+
sourceType: z.string(),
|
|
824
|
+
verificationState: z.string(),
|
|
825
|
+
}),
|
|
826
|
+
responseBody: z.object({
|
|
827
|
+
item: z.object({}).passthrough().describe("Updated memory item"),
|
|
828
|
+
}),
|
|
737
829
|
handler: (ctx) => handleUpdateMemoryItem(ctx),
|
|
738
830
|
},
|
|
739
831
|
{
|
|
740
832
|
endpoint: "memory-items/:id",
|
|
741
833
|
method: "DELETE",
|
|
742
834
|
policyKey: "memory-items",
|
|
835
|
+
summary: "Delete a memory item",
|
|
836
|
+
description: "Delete a memory item and its embeddings.",
|
|
837
|
+
tags: ["memory"],
|
|
838
|
+
responseBody: z.object({
|
|
839
|
+
ok: z.boolean(),
|
|
840
|
+
}),
|
|
743
841
|
handler: (ctx) => handleDeleteMemoryItem(ctx),
|
|
744
842
|
},
|
|
745
843
|
];
|