@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
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* the same pattern as other gateway-forwarded control-plane endpoints.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
10
12
|
import { getDb } from "../../memory/db-connection.js";
|
|
11
13
|
import { getMaxMigrationVersion } from "../../memory/migrations/registry.js";
|
|
12
14
|
import { rollbackMemoryMigration } from "../../memory/migrations/validate-migration-state.js";
|
|
@@ -25,6 +27,29 @@ export function migrationRollbackRouteDefinitions(): RouteDefinition[] {
|
|
|
25
27
|
{
|
|
26
28
|
endpoint: "admin/rollback-migrations",
|
|
27
29
|
method: "POST",
|
|
30
|
+
summary: "Rollback migrations",
|
|
31
|
+
description:
|
|
32
|
+
"Roll back DB and/or workspace migrations to a specified target version. Restricted to gateway service principals.",
|
|
33
|
+
tags: ["admin"],
|
|
34
|
+
requestBody: z.object({
|
|
35
|
+
targetDbVersion: z
|
|
36
|
+
.number()
|
|
37
|
+
.int()
|
|
38
|
+
.describe("Target DB migration version"),
|
|
39
|
+
targetWorkspaceMigrationId: z
|
|
40
|
+
.string()
|
|
41
|
+
.describe("Target workspace migration ID"),
|
|
42
|
+
rollbackToRegistryCeiling: z
|
|
43
|
+
.boolean()
|
|
44
|
+
.describe("Auto-determine targets from daemon registry ceilings"),
|
|
45
|
+
}),
|
|
46
|
+
responseBody: z.object({
|
|
47
|
+
ok: z.boolean(),
|
|
48
|
+
rolledBack: z
|
|
49
|
+
.object({})
|
|
50
|
+
.passthrough()
|
|
51
|
+
.describe("Lists of rolled-back DB and workspace migrations"),
|
|
52
|
+
}),
|
|
28
53
|
handler: async ({ req }) => {
|
|
29
54
|
let body: unknown;
|
|
30
55
|
try {
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import { join } from "node:path";
|
|
15
15
|
import { Database } from "bun:sqlite";
|
|
16
16
|
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
17
19
|
import { invalidateConfigCache } from "../../config/loader.js";
|
|
18
20
|
import { getDb, resetDb } from "../../memory/db-connection.js";
|
|
19
21
|
import { validateMigrationState } from "../../memory/migrations/validate-migration-state.js";
|
|
@@ -474,21 +476,59 @@ export function migrationRouteDefinitions(): RouteDefinition[] {
|
|
|
474
476
|
{
|
|
475
477
|
endpoint: "migrations/validate",
|
|
476
478
|
method: "POST",
|
|
479
|
+
summary: "Validate a .vbundle archive",
|
|
480
|
+
description:
|
|
481
|
+
"Upload a .vbundle archive for validation. Accepts raw binary or multipart form data.",
|
|
482
|
+
tags: ["migrations"],
|
|
483
|
+
responseBody: z.object({
|
|
484
|
+
is_valid: z.boolean(),
|
|
485
|
+
errors: z.array(z.unknown()),
|
|
486
|
+
manifest: z.object({}).passthrough(),
|
|
487
|
+
}),
|
|
477
488
|
handler: async ({ req }) => handleMigrationValidate(req),
|
|
478
489
|
},
|
|
479
490
|
{
|
|
480
491
|
endpoint: "migrations/export",
|
|
481
492
|
method: "POST",
|
|
493
|
+
summary: "Export a .vbundle archive",
|
|
494
|
+
description:
|
|
495
|
+
"Generate and download a .vbundle archive of the assistant's data. Optional JSON body for metadata.",
|
|
496
|
+
tags: ["migrations"],
|
|
497
|
+
requestBody: z.object({
|
|
498
|
+
description: z.string().describe("Human-readable export description"),
|
|
499
|
+
}),
|
|
482
500
|
handler: async ({ req }) => handleMigrationExport(req),
|
|
483
501
|
},
|
|
484
502
|
{
|
|
485
503
|
endpoint: "migrations/import-preflight",
|
|
486
504
|
method: "POST",
|
|
505
|
+
summary: "Dry-run import analysis",
|
|
506
|
+
description:
|
|
507
|
+
"Validate a .vbundle archive and return a report of what would change on import without modifying data.",
|
|
508
|
+
tags: ["migrations"],
|
|
509
|
+
responseBody: z.object({
|
|
510
|
+
can_import: z.boolean(),
|
|
511
|
+
summary: z.object({}).passthrough(),
|
|
512
|
+
files: z.array(z.unknown()),
|
|
513
|
+
conflicts: z.array(z.unknown()),
|
|
514
|
+
manifest: z.object({}).passthrough(),
|
|
515
|
+
}),
|
|
487
516
|
handler: async ({ req }) => handleMigrationImportPreflight(req),
|
|
488
517
|
},
|
|
489
518
|
{
|
|
490
519
|
endpoint: "migrations/import",
|
|
491
520
|
method: "POST",
|
|
521
|
+
summary: "Import a .vbundle archive",
|
|
522
|
+
description:
|
|
523
|
+
"Commit a .vbundle archive import to disk — destructive. Backs up existing files before overwriting.",
|
|
524
|
+
tags: ["migrations"],
|
|
525
|
+
responseBody: z.object({
|
|
526
|
+
success: z.boolean(),
|
|
527
|
+
summary: z.object({}).passthrough(),
|
|
528
|
+
files: z.array(z.unknown()),
|
|
529
|
+
manifest: z.object({}).passthrough(),
|
|
530
|
+
warnings: z.array(z.unknown()),
|
|
531
|
+
}),
|
|
492
532
|
handler: async ({ req }) => handleMigrationImport(req),
|
|
493
533
|
},
|
|
494
534
|
];
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { eq } from "drizzle-orm";
|
|
9
|
+
import { z } from "zod";
|
|
9
10
|
|
|
10
11
|
import { getDb } from "../../memory/db.js";
|
|
11
12
|
import { notificationDeliveries } from "../../memory/schema.js";
|
|
@@ -19,6 +20,25 @@ export function notificationRouteDefinitions(): RouteDefinition[] {
|
|
|
19
20
|
endpoint: "notification-intent-result",
|
|
20
21
|
method: "POST",
|
|
21
22
|
policyKey: "notification-intent-result",
|
|
23
|
+
summary: "Report notification delivery result",
|
|
24
|
+
description:
|
|
25
|
+
"Client acknowledgment for local notification delivery outcome.",
|
|
26
|
+
tags: ["notifications"],
|
|
27
|
+
requestBody: z.object({
|
|
28
|
+
deliveryId: z.string().describe("Notification delivery ID"),
|
|
29
|
+
success: z.boolean().describe("Whether delivery succeeded").optional(),
|
|
30
|
+
errorMessage: z
|
|
31
|
+
.string()
|
|
32
|
+
.describe("Error message if delivery failed")
|
|
33
|
+
.optional(),
|
|
34
|
+
errorCode: z
|
|
35
|
+
.string()
|
|
36
|
+
.describe("Error code if delivery failed")
|
|
37
|
+
.optional(),
|
|
38
|
+
}),
|
|
39
|
+
responseBody: z.object({
|
|
40
|
+
ok: z.boolean(),
|
|
41
|
+
}),
|
|
22
42
|
handler: async ({ req }) => {
|
|
23
43
|
const body = (await req.json()) as {
|
|
24
44
|
deliveryId?: string;
|
|
@@ -21,9 +21,13 @@ import {
|
|
|
21
21
|
import { httpError } from "../http-errors.js";
|
|
22
22
|
import type { RouteDefinition } from "../http-router.js";
|
|
23
23
|
|
|
24
|
-
function parseGrantedScopes(
|
|
24
|
+
function parseGrantedScopes(
|
|
25
|
+
grantedScopes: string | string[] | null | undefined,
|
|
26
|
+
): string[] {
|
|
25
27
|
if (Array.isArray(grantedScopes)) {
|
|
26
|
-
return grantedScopes.filter(
|
|
28
|
+
return grantedScopes.filter(
|
|
29
|
+
(scope): scope is string => typeof scope === "string",
|
|
30
|
+
);
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
if (typeof grantedScopes !== "string" || grantedScopes.trim() === "") {
|
|
@@ -77,7 +81,8 @@ export function oauthAppsRouteDefinitions(): RouteDefinition[] {
|
|
|
77
81
|
description: providerRow.description ?? null,
|
|
78
82
|
dashboard_url: providerRow.dashboardUrl ?? null,
|
|
79
83
|
client_id_placeholder: providerRow.clientIdPlaceholder ?? null,
|
|
80
|
-
requires_client_secret: providerRow.requiresClientSecret ?? 1,
|
|
84
|
+
requires_client_secret: !!(providerRow.requiresClientSecret ?? 1),
|
|
85
|
+
supports_managed_mode: !!providerRow.managedServiceConfigKey,
|
|
81
86
|
}
|
|
82
87
|
: null;
|
|
83
88
|
|
|
@@ -159,7 +164,11 @@ export function oauthAppsRouteDefinitions(): RouteDefinition[] {
|
|
|
159
164
|
handler: async ({ params }) => {
|
|
160
165
|
const app = getApp(params.id);
|
|
161
166
|
if (!app) {
|
|
162
|
-
return httpError(
|
|
167
|
+
return httpError(
|
|
168
|
+
"NOT_FOUND",
|
|
169
|
+
`OAuth app not found: ${params.id}`,
|
|
170
|
+
404,
|
|
171
|
+
);
|
|
163
172
|
}
|
|
164
173
|
|
|
165
174
|
// Disconnect all connections for this app first to clean up tokens.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Pairing HTTP route handlers for device pairing flow.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
5
7
|
import {
|
|
6
8
|
hashDeviceId,
|
|
7
9
|
isDeviceApproved,
|
|
@@ -417,6 +419,19 @@ export function pairingRouteDefinitions(deps: {
|
|
|
417
419
|
{
|
|
418
420
|
endpoint: "pairing/register",
|
|
419
421
|
method: "POST",
|
|
422
|
+
summary: "Register pairing request",
|
|
423
|
+
description:
|
|
424
|
+
"Pre-register a pairing request when the QR code is displayed.",
|
|
425
|
+
tags: ["pairing"],
|
|
426
|
+
requestBody: z.object({
|
|
427
|
+
pairingRequestId: z.string(),
|
|
428
|
+
pairingSecret: z.string(),
|
|
429
|
+
gatewayUrl: z.string(),
|
|
430
|
+
localLanUrl: z.string().optional(),
|
|
431
|
+
}),
|
|
432
|
+
responseBody: z.object({
|
|
433
|
+
ok: z.boolean(),
|
|
434
|
+
}),
|
|
420
435
|
handler: async ({ req }) =>
|
|
421
436
|
handlePairingRegister(req, deps.getPairingContext()),
|
|
422
437
|
},
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* require `settings.read`.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
12
14
|
import {
|
|
13
15
|
getActiveRestartToken,
|
|
14
16
|
handleRecordingPause,
|
|
@@ -298,36 +300,106 @@ export function recordingRouteDefinitions(deps: {
|
|
|
298
300
|
endpoint: "recordings/start",
|
|
299
301
|
method: "POST",
|
|
300
302
|
policyKey: "recordings/start",
|
|
303
|
+
summary: "Start recording",
|
|
304
|
+
description: "Start a screen recording for a conversation.",
|
|
305
|
+
tags: ["recordings"],
|
|
306
|
+
requestBody: z.object({
|
|
307
|
+
conversationId: z.string(),
|
|
308
|
+
options: z
|
|
309
|
+
.object({})
|
|
310
|
+
.passthrough()
|
|
311
|
+
.describe("Recording options")
|
|
312
|
+
.optional(),
|
|
313
|
+
}),
|
|
314
|
+
responseBody: z.object({
|
|
315
|
+
recordingId: z.string(),
|
|
316
|
+
}),
|
|
301
317
|
handler: async ({ req }) => handleStartRecording(req, getDeps()),
|
|
302
318
|
},
|
|
303
319
|
{
|
|
304
320
|
endpoint: "recordings/stop",
|
|
305
321
|
method: "POST",
|
|
306
322
|
policyKey: "recordings/stop",
|
|
323
|
+
summary: "Stop recording",
|
|
324
|
+
description: "Stop the active screen recording.",
|
|
325
|
+
tags: ["recordings"],
|
|
326
|
+
requestBody: z.object({
|
|
327
|
+
conversationId: z.string(),
|
|
328
|
+
}),
|
|
329
|
+
responseBody: z.object({
|
|
330
|
+
recordingId: z.string(),
|
|
331
|
+
stopped: z.boolean(),
|
|
332
|
+
}),
|
|
307
333
|
handler: async ({ req }) => handleStopRecording(req, getDeps()),
|
|
308
334
|
},
|
|
309
335
|
{
|
|
310
336
|
endpoint: "recordings/pause",
|
|
311
337
|
method: "POST",
|
|
312
338
|
policyKey: "recordings/pause",
|
|
339
|
+
summary: "Pause recording",
|
|
340
|
+
description: "Pause the active screen recording.",
|
|
341
|
+
tags: ["recordings"],
|
|
342
|
+
requestBody: z.object({
|
|
343
|
+
conversationId: z.string(),
|
|
344
|
+
}),
|
|
345
|
+
responseBody: z.object({
|
|
346
|
+
recordingId: z.string(),
|
|
347
|
+
paused: z.boolean(),
|
|
348
|
+
}),
|
|
313
349
|
handler: async ({ req }) => handlePauseRecording(req, getDeps()),
|
|
314
350
|
},
|
|
315
351
|
{
|
|
316
352
|
endpoint: "recordings/resume",
|
|
317
353
|
method: "POST",
|
|
318
354
|
policyKey: "recordings/resume",
|
|
355
|
+
summary: "Resume recording",
|
|
356
|
+
description: "Resume a paused screen recording.",
|
|
357
|
+
tags: ["recordings"],
|
|
358
|
+
requestBody: z.object({
|
|
359
|
+
conversationId: z.string(),
|
|
360
|
+
}),
|
|
361
|
+
responseBody: z.object({
|
|
362
|
+
recordingId: z.string(),
|
|
363
|
+
resumed: z.boolean(),
|
|
364
|
+
}),
|
|
319
365
|
handler: async ({ req }) => handleResumeRecording(req, getDeps()),
|
|
320
366
|
},
|
|
321
367
|
{
|
|
322
368
|
endpoint: "recordings/status",
|
|
323
369
|
method: "GET",
|
|
324
370
|
policyKey: "recordings/status",
|
|
371
|
+
summary: "Get recording status",
|
|
372
|
+
description: "Return the current recording state.",
|
|
373
|
+
tags: ["recordings"],
|
|
374
|
+
responseBody: z.object({
|
|
375
|
+
idle: z.boolean(),
|
|
376
|
+
restartInProgress: z.boolean(),
|
|
377
|
+
}),
|
|
325
378
|
handler: () => handleGetRecordingStatus(),
|
|
326
379
|
},
|
|
327
380
|
{
|
|
328
381
|
endpoint: "recordings/status",
|
|
329
382
|
method: "POST",
|
|
330
383
|
policyKey: "recordings/status:POST",
|
|
384
|
+
summary: "Post recording status",
|
|
385
|
+
description: "Recording lifecycle callback from the client.",
|
|
386
|
+
tags: ["recordings"],
|
|
387
|
+
requestBody: z.object({
|
|
388
|
+
conversationId: z.string(),
|
|
389
|
+
status: z
|
|
390
|
+
.string()
|
|
391
|
+
.describe(
|
|
392
|
+
"started, stopped, failed, restart_cancelled, paused, resumed",
|
|
393
|
+
),
|
|
394
|
+
filePath: z.string().optional(),
|
|
395
|
+
durationMs: z.number().optional(),
|
|
396
|
+
error: z.string().optional(),
|
|
397
|
+
attachToConversationId: z.string().optional(),
|
|
398
|
+
operationToken: z.string().optional(),
|
|
399
|
+
}),
|
|
400
|
+
responseBody: z.object({
|
|
401
|
+
ok: z.boolean(),
|
|
402
|
+
}),
|
|
331
403
|
handler: async ({ req }) => handlePostRecordingStatus(req, getDeps()),
|
|
332
404
|
},
|
|
333
405
|
];
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* HTTP route handlers for schedule management.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
7
9
|
import { bootstrapConversation } from "../../memory/conversation-bootstrap.js";
|
|
8
10
|
import {
|
|
9
11
|
cancelSchedule,
|
|
@@ -112,11 +114,27 @@ function handleUpdateSchedule(
|
|
|
112
114
|
): Response {
|
|
113
115
|
const updates: Record<string, unknown> = {};
|
|
114
116
|
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
+
if (
|
|
118
|
+
"mode" in body &&
|
|
119
|
+
!VALID_MODES.includes(body.mode as (typeof VALID_MODES)[number])
|
|
120
|
+
) {
|
|
121
|
+
return httpError(
|
|
122
|
+
"BAD_REQUEST",
|
|
123
|
+
`Invalid mode: must be one of ${VALID_MODES.join(", ")}`,
|
|
124
|
+
400,
|
|
125
|
+
);
|
|
117
126
|
}
|
|
118
|
-
if (
|
|
119
|
-
|
|
127
|
+
if (
|
|
128
|
+
"routingIntent" in body &&
|
|
129
|
+
!VALID_ROUTING_INTENTS.includes(
|
|
130
|
+
body.routingIntent as (typeof VALID_ROUTING_INTENTS)[number],
|
|
131
|
+
)
|
|
132
|
+
) {
|
|
133
|
+
return httpError(
|
|
134
|
+
"BAD_REQUEST",
|
|
135
|
+
`Invalid routingIntent: must be one of ${VALID_ROUTING_INTENTS.join(", ")}`,
|
|
136
|
+
400,
|
|
137
|
+
);
|
|
120
138
|
}
|
|
121
139
|
|
|
122
140
|
for (const key of [
|
|
@@ -276,12 +294,27 @@ export function scheduleRouteDefinitions(deps: {
|
|
|
276
294
|
endpoint: "schedules",
|
|
277
295
|
method: "GET",
|
|
278
296
|
policyKey: "schedules",
|
|
297
|
+
summary: "List schedules",
|
|
298
|
+
description: "Return all scheduled jobs.",
|
|
299
|
+
tags: ["schedules"],
|
|
300
|
+
responseBody: z.object({
|
|
301
|
+
schedules: z.array(z.unknown()).describe("Schedule objects"),
|
|
302
|
+
}),
|
|
279
303
|
handler: () => handleListSchedules(),
|
|
280
304
|
},
|
|
281
305
|
{
|
|
282
306
|
endpoint: "schedules/:id/toggle",
|
|
283
307
|
method: "POST",
|
|
284
308
|
policyKey: "schedules/toggle",
|
|
309
|
+
summary: "Toggle schedule",
|
|
310
|
+
description: "Enable or disable a schedule.",
|
|
311
|
+
tags: ["schedules"],
|
|
312
|
+
requestBody: z.object({
|
|
313
|
+
enabled: z.boolean().describe("New enabled state"),
|
|
314
|
+
}),
|
|
315
|
+
responseBody: z.object({
|
|
316
|
+
schedules: z.array(z.unknown()).describe("Updated schedule list"),
|
|
317
|
+
}),
|
|
285
318
|
handler: async ({ req, params }) => {
|
|
286
319
|
const body = (await req.json()) as { enabled?: boolean };
|
|
287
320
|
if (body.enabled === undefined) {
|
|
@@ -294,16 +327,43 @@ export function scheduleRouteDefinitions(deps: {
|
|
|
294
327
|
endpoint: "schedules/:id",
|
|
295
328
|
method: "DELETE",
|
|
296
329
|
policyKey: "schedules",
|
|
330
|
+
summary: "Delete schedule",
|
|
331
|
+
description: "Remove a schedule by ID.",
|
|
332
|
+
tags: ["schedules"],
|
|
333
|
+
responseBody: z.object({
|
|
334
|
+
schedules: z.array(z.unknown()).describe("Updated schedule list"),
|
|
335
|
+
}),
|
|
297
336
|
handler: ({ params }) => handleDeleteSchedule(params.id),
|
|
298
337
|
},
|
|
299
338
|
{
|
|
300
339
|
endpoint: "schedules/:id",
|
|
301
340
|
method: "PATCH",
|
|
302
341
|
policyKey: "schedules",
|
|
342
|
+
summary: "Update schedule",
|
|
343
|
+
description: "Partially update fields on a schedule.",
|
|
344
|
+
tags: ["schedules"],
|
|
345
|
+
requestBody: z.object({
|
|
346
|
+
name: z.string(),
|
|
347
|
+
expression: z.string(),
|
|
348
|
+
timezone: z.string(),
|
|
349
|
+
message: z.string(),
|
|
350
|
+
mode: z.string().describe("notify or execute"),
|
|
351
|
+
routingIntent: z
|
|
352
|
+
.string()
|
|
353
|
+
.describe("single_channel, multi_channel, or all_channels"),
|
|
354
|
+
quiet: z.boolean(),
|
|
355
|
+
}),
|
|
356
|
+
responseBody: z.object({
|
|
357
|
+
schedules: z.array(z.unknown()).describe("Updated schedule list"),
|
|
358
|
+
}),
|
|
303
359
|
handler: async ({ req, params }) => {
|
|
304
360
|
const body: unknown = await req.json();
|
|
305
361
|
if (typeof body !== "object" || !body || Array.isArray(body)) {
|
|
306
|
-
return httpError(
|
|
362
|
+
return httpError(
|
|
363
|
+
"BAD_REQUEST",
|
|
364
|
+
"Request body must be a JSON object",
|
|
365
|
+
400,
|
|
366
|
+
);
|
|
307
367
|
}
|
|
308
368
|
return handleUpdateSchedule(params.id, body as Record<string, unknown>);
|
|
309
369
|
},
|
|
@@ -312,6 +372,12 @@ export function scheduleRouteDefinitions(deps: {
|
|
|
312
372
|
endpoint: "schedules/:id/run",
|
|
313
373
|
method: "POST",
|
|
314
374
|
policyKey: "schedules/run",
|
|
375
|
+
summary: "Run schedule now",
|
|
376
|
+
description: "Trigger an immediate execution of a schedule.",
|
|
377
|
+
tags: ["schedules"],
|
|
378
|
+
responseBody: z.object({
|
|
379
|
+
schedules: z.array(z.unknown()).describe("Updated schedule list"),
|
|
380
|
+
}),
|
|
315
381
|
handler: async ({ params }) =>
|
|
316
382
|
handleRunScheduleNow(params.id, deps.sendMessageDeps),
|
|
317
383
|
},
|
|
@@ -319,6 +385,12 @@ export function scheduleRouteDefinitions(deps: {
|
|
|
319
385
|
endpoint: "schedules/:id/cancel",
|
|
320
386
|
method: "POST",
|
|
321
387
|
policyKey: "schedules/cancel",
|
|
388
|
+
summary: "Cancel schedule",
|
|
389
|
+
description: "Cancel a pending schedule.",
|
|
390
|
+
tags: ["schedules"],
|
|
391
|
+
responseBody: z.object({
|
|
392
|
+
schedules: z.array(z.unknown()).describe("Updated schedule list"),
|
|
393
|
+
}),
|
|
322
394
|
handler: ({ params }) => handleCancelSchedule(params.id),
|
|
323
395
|
},
|
|
324
396
|
];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
setPlatformAssistantId,
|
|
3
5
|
setPlatformBaseUrl,
|
|
@@ -104,7 +106,7 @@ async function queueApiKeyPropagation(
|
|
|
104
106
|
|
|
105
107
|
export async function handleAddSecret(
|
|
106
108
|
req: Request,
|
|
107
|
-
|
|
109
|
+
deps?: SecretRouteDeps,
|
|
108
110
|
): Promise<Response> {
|
|
109
111
|
let body: { type?: string; name?: string; value?: string };
|
|
110
112
|
try {
|
|
@@ -190,9 +192,7 @@ export async function handleAddSecret(
|
|
|
190
192
|
500,
|
|
191
193
|
);
|
|
192
194
|
}
|
|
193
|
-
|
|
194
|
-
invalidateConfigCache();
|
|
195
|
-
await initializeProviders(getConfig());
|
|
195
|
+
await refreshProvidersAfterSecretChange(deps);
|
|
196
196
|
log.info({ provider: name }, "API key updated via HTTP");
|
|
197
197
|
return Response.json({ success: true, type, name }, { status: 201 });
|
|
198
198
|
}
|
|
@@ -273,12 +273,12 @@ export async function handleAddSecret(
|
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
275
|
if (isManagedProxyCredential(service, field)) {
|
|
276
|
-
await
|
|
276
|
+
await refreshProvidersAfterSecretChange(deps);
|
|
277
277
|
if (service === "vellum" && field === "assistant_api_key") {
|
|
278
278
|
// Push the API key to CES so managed credential materialization
|
|
279
279
|
// works even though the handshake ran before the key was available.
|
|
280
280
|
const generation = ++apiKeyGeneration;
|
|
281
|
-
const cesClient = getCesClient?.();
|
|
281
|
+
const cesClient = deps?.getCesClient?.();
|
|
282
282
|
if (cesClient) {
|
|
283
283
|
if (cesClient.isReady()) {
|
|
284
284
|
try {
|
|
@@ -392,7 +392,10 @@ export async function handleReadSecret(req: Request): Promise<Response> {
|
|
|
392
392
|
}
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
export async function handleDeleteSecret(
|
|
395
|
+
export async function handleDeleteSecret(
|
|
396
|
+
req: Request,
|
|
397
|
+
deps?: SecretRouteDeps,
|
|
398
|
+
): Promise<Response> {
|
|
396
399
|
let body: { type?: string; name?: string };
|
|
397
400
|
try {
|
|
398
401
|
body = (await req.json()) as { type?: string; name?: string };
|
|
@@ -436,9 +439,7 @@ export async function handleDeleteSecret(req: Request): Promise<Response> {
|
|
|
436
439
|
500,
|
|
437
440
|
);
|
|
438
441
|
}
|
|
439
|
-
|
|
440
|
-
invalidateConfigCache();
|
|
441
|
-
await initializeProviders(getConfig());
|
|
442
|
+
await refreshProvidersAfterSecretChange(deps);
|
|
442
443
|
log.info({ provider: name }, "API key deleted via HTTP");
|
|
443
444
|
return Response.json({ success: true, type, name });
|
|
444
445
|
}
|
|
@@ -486,7 +487,7 @@ export async function handleDeleteSecret(req: Request): Promise<Response> {
|
|
|
486
487
|
setSentryUserId(undefined);
|
|
487
488
|
}
|
|
488
489
|
if (isManagedProxyCredential(service, field)) {
|
|
489
|
-
await
|
|
490
|
+
await refreshProvidersAfterSecretChange(deps);
|
|
490
491
|
}
|
|
491
492
|
log.info({ service, field }, "Credential deleted via HTTP");
|
|
492
493
|
return Response.json({ success: true, type, name });
|
|
@@ -532,7 +533,7 @@ export async function handleListSecrets(): Promise<Response> {
|
|
|
532
533
|
return { type: "api_key" as const, name: account };
|
|
533
534
|
});
|
|
534
535
|
|
|
535
|
-
return Response.json({ secrets });
|
|
536
|
+
return Response.json({ secrets, accounts: secrets });
|
|
536
537
|
} catch (err) {
|
|
537
538
|
const message = err instanceof Error ? err.message : String(err);
|
|
538
539
|
return httpError("INTERNAL_ERROR", message, 500);
|
|
@@ -546,6 +547,30 @@ export async function handleListSecrets(): Promise<Response> {
|
|
|
546
547
|
export interface SecretRouteDeps {
|
|
547
548
|
/** Accessor for the CES client, used to push API key updates after hatch. */
|
|
548
549
|
getCesClient?: () => CesClient | undefined;
|
|
550
|
+
/**
|
|
551
|
+
* Called after provider-affecting credentials change so live conversations
|
|
552
|
+
* can be reloaded with fresh provider instances.
|
|
553
|
+
*/
|
|
554
|
+
onProviderCredentialsChanged?: () => void | Promise<void>;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async function refreshProvidersAfterSecretChange(
|
|
558
|
+
deps?: SecretRouteDeps,
|
|
559
|
+
): Promise<void> {
|
|
560
|
+
clearEmbeddingBackendCache();
|
|
561
|
+
invalidateConfigCache();
|
|
562
|
+
await initializeProviders(getConfig());
|
|
563
|
+
|
|
564
|
+
if (!deps?.onProviderCredentialsChanged) return;
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
await deps.onProviderCredentialsChanged();
|
|
568
|
+
} catch (err) {
|
|
569
|
+
log.warn(
|
|
570
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
571
|
+
"Failed to refresh live conversations after provider credential change",
|
|
572
|
+
);
|
|
573
|
+
}
|
|
549
574
|
}
|
|
550
575
|
|
|
551
576
|
export function secretRouteDefinitions(
|
|
@@ -555,22 +580,82 @@ export function secretRouteDefinitions(
|
|
|
555
580
|
{
|
|
556
581
|
endpoint: "secrets",
|
|
557
582
|
method: "POST",
|
|
558
|
-
handler: async ({ req }) => handleAddSecret(req, deps
|
|
583
|
+
handler: async ({ req }) => handleAddSecret(req, deps),
|
|
584
|
+
summary: "Add a secret",
|
|
585
|
+
description:
|
|
586
|
+
"Store a new secret (API key, OAuth token, etc.) in the credential vault.",
|
|
587
|
+
tags: ["secrets"],
|
|
588
|
+
requestBody: z.object({
|
|
589
|
+
type: z.string().describe("Secret type: 'api_key' or 'credential'"),
|
|
590
|
+
name: z.string().describe("Unique name for the secret"),
|
|
591
|
+
value: z.string().describe("Secret value to store"),
|
|
592
|
+
}),
|
|
593
|
+
responseBody: z.object({
|
|
594
|
+
success: z.boolean(),
|
|
595
|
+
type: z.string(),
|
|
596
|
+
name: z.string(),
|
|
597
|
+
}),
|
|
559
598
|
},
|
|
560
599
|
{
|
|
561
600
|
endpoint: "secrets",
|
|
562
601
|
method: "DELETE",
|
|
563
|
-
handler: async ({ req }) => handleDeleteSecret(req),
|
|
602
|
+
handler: async ({ req }) => handleDeleteSecret(req, deps),
|
|
603
|
+
summary: "Delete a secret",
|
|
604
|
+
description: "Remove a secret from the credential vault by name.",
|
|
605
|
+
tags: ["secrets"],
|
|
606
|
+
requestBody: z.object({
|
|
607
|
+
type: z.string().describe("Secret type: 'api_key' or 'credential'"),
|
|
608
|
+
name: z.string().describe("Name of the secret to delete"),
|
|
609
|
+
}),
|
|
610
|
+
responseBody: z.object({
|
|
611
|
+
success: z.boolean(),
|
|
612
|
+
type: z.string(),
|
|
613
|
+
name: z.string(),
|
|
614
|
+
}),
|
|
564
615
|
},
|
|
565
616
|
{
|
|
566
617
|
endpoint: "secrets",
|
|
567
618
|
method: "GET",
|
|
568
619
|
handler: async () => handleListSecrets(),
|
|
620
|
+
summary: "List secrets",
|
|
621
|
+
description: "Return the names (not values) of all stored secrets.",
|
|
622
|
+
tags: ["secrets"],
|
|
623
|
+
responseBody: z.object({
|
|
624
|
+
secrets: z
|
|
625
|
+
.array(z.unknown())
|
|
626
|
+
.describe("List of secret metadata entries, each with type and name"),
|
|
627
|
+
accounts: z
|
|
628
|
+
.array(z.unknown())
|
|
629
|
+
.describe("Alias for secrets (same data)"),
|
|
630
|
+
}),
|
|
569
631
|
},
|
|
570
632
|
{
|
|
571
633
|
endpoint: "secrets/read",
|
|
572
634
|
method: "POST",
|
|
573
635
|
handler: async ({ req }) => handleReadSecret(req),
|
|
636
|
+
summary: "Read a secret value",
|
|
637
|
+
description: "Retrieve the decrypted value of a stored secret by name.",
|
|
638
|
+
tags: ["secrets"],
|
|
639
|
+
requestBody: z.object({
|
|
640
|
+
type: z.string().describe("Secret type: 'api_key' or 'credential'"),
|
|
641
|
+
name: z.string().describe("Name of the secret to read"),
|
|
642
|
+
reveal: z
|
|
643
|
+
.boolean()
|
|
644
|
+
.describe(
|
|
645
|
+
"If true, return the decrypted value; otherwise return a masked version",
|
|
646
|
+
)
|
|
647
|
+
.optional(),
|
|
648
|
+
}),
|
|
649
|
+
responseBody: z.object({
|
|
650
|
+
found: z.boolean(),
|
|
651
|
+
value: z
|
|
652
|
+
.string()
|
|
653
|
+
.describe("Decrypted value (only when reveal=true and found)"),
|
|
654
|
+
masked: z
|
|
655
|
+
.string()
|
|
656
|
+
.describe("Masked value (when reveal=false and found)"),
|
|
657
|
+
unreachable: z.boolean(),
|
|
658
|
+
}),
|
|
574
659
|
},
|
|
575
660
|
];
|
|
576
661
|
}
|