@vellumai/assistant 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +5 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +325 -3
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +3 -2
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +60 -36
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +266 -10
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +55 -13
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +31 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/types.ts +108 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +329 -317
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +38 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/feature-flag-registry.json +41 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +7 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +3 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop.ts +169 -9
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +16 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +98 -23
- package/src/daemon/lifecycle.ts +45 -35
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +49 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +1 -1
- package/src/daemon/pkb-reminder-builder.ts +1 -1
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +21 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +41 -0
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +22 -0
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +110 -10
- package/src/memory/db-init.ts +6 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/conversation-graph-memory.ts +31 -15
- package/src/memory/graph/tools.ts +3 -3
- package/src/memory/indexer.ts +34 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/inference.ts +1 -3
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/injection.test.ts +98 -8
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/injection.ts +32 -6
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +35 -5
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/emit-signal.ts +20 -1
- package/src/notifications/home-feed-side-effect.ts +54 -0
- package/src/notifications/signal.ts +3 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +36 -3
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +105 -32
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +31 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +12 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -166
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/providers/__tests__/inference.test.ts +22 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/connection-resolution.ts +7 -0
- package/src/providers/inference/adapter-factory.ts +41 -4
- package/src/providers/inference/connections.ts +74 -29
- package/src/providers/inference/resolve-auth.ts +12 -4
- package/src/providers/model-catalog.ts +294 -12
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/registry.ts +22 -14
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +42 -14
- package/src/runtime/auth/route-policy.ts +8 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-types.ts +19 -0
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +40 -35
- package/src/runtime/routes/conversation-routes.ts +90 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +15 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
updateMessageContent,
|
|
21
21
|
updateMessageContentAndMetadata,
|
|
22
22
|
} from "../../../memory/conversation-crud.js";
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
findMessageBySourceId,
|
|
25
|
+
recordInbound,
|
|
26
|
+
} from "../../../memory/delivery-crud.js";
|
|
24
27
|
import {
|
|
25
28
|
mergeSlackMetadata,
|
|
26
29
|
readSlackMetadata,
|
|
@@ -39,6 +42,7 @@ export interface EditInterceptParams {
|
|
|
39
42
|
conversationExternalId: string;
|
|
40
43
|
externalMessageId: string;
|
|
41
44
|
sourceMessageId: string;
|
|
45
|
+
sourceThreadId?: string;
|
|
42
46
|
canonicalAssistantId: string;
|
|
43
47
|
assistantId: string;
|
|
44
48
|
content: string | undefined;
|
|
@@ -61,6 +65,7 @@ export async function handleEditIntercept(
|
|
|
61
65
|
conversationExternalId,
|
|
62
66
|
externalMessageId,
|
|
63
67
|
sourceMessageId,
|
|
68
|
+
sourceThreadId,
|
|
64
69
|
canonicalAssistantId,
|
|
65
70
|
assistantId,
|
|
66
71
|
content,
|
|
@@ -71,7 +76,7 @@ export async function handleEditIntercept(
|
|
|
71
76
|
sourceChannel,
|
|
72
77
|
conversationExternalId,
|
|
73
78
|
externalMessageId,
|
|
74
|
-
{ sourceMessageId, assistantId: canonicalAssistantId },
|
|
79
|
+
{ sourceMessageId, sourceThreadId, assistantId: canonicalAssistantId },
|
|
75
80
|
);
|
|
76
81
|
|
|
77
82
|
if (editResult.duplicate) {
|
|
@@ -145,6 +150,7 @@ export async function handleEditIntercept(
|
|
|
145
150
|
messageId: original.messageId,
|
|
146
151
|
conversationExternalId,
|
|
147
152
|
sourceMessageId,
|
|
153
|
+
sourceThreadId,
|
|
148
154
|
newContent,
|
|
149
155
|
});
|
|
150
156
|
} else {
|
|
@@ -203,10 +209,16 @@ function applySlackEditMetadata(params: {
|
|
|
203
209
|
messageId: string;
|
|
204
210
|
conversationExternalId: string;
|
|
205
211
|
sourceMessageId: string;
|
|
212
|
+
sourceThreadId?: string;
|
|
206
213
|
newContent: string;
|
|
207
214
|
}): void {
|
|
208
|
-
const {
|
|
209
|
-
|
|
215
|
+
const {
|
|
216
|
+
messageId,
|
|
217
|
+
conversationExternalId,
|
|
218
|
+
sourceMessageId,
|
|
219
|
+
sourceThreadId,
|
|
220
|
+
newContent,
|
|
221
|
+
} = params;
|
|
210
222
|
|
|
211
223
|
const row = getMessageById(messageId);
|
|
212
224
|
const outerMetadata: Record<string, unknown> =
|
|
@@ -230,6 +242,7 @@ function applySlackEditMetadata(params: {
|
|
|
230
242
|
source: "slack" as const,
|
|
231
243
|
channelId: conversationExternalId,
|
|
232
244
|
channelTs: sourceMessageId,
|
|
245
|
+
...(sourceThreadId ? { threadTs: sourceThreadId } : {}),
|
|
233
246
|
eventKind: "message" as const,
|
|
234
247
|
}),
|
|
235
248
|
editedAt,
|
|
@@ -25,6 +25,7 @@ import { ROUTES as BROWSER_ROUTES } from "./browser-routes.js";
|
|
|
25
25
|
import { ROUTES as BTW_ROUTES } from "./btw-routes.js";
|
|
26
26
|
import { ROUTES as CACHE_ROUTES } from "./cache-routes.js";
|
|
27
27
|
import { ROUTES as CALL_ROUTES } from "./call-routes.js";
|
|
28
|
+
import { ROUTES as CHANNEL_AVAILABILITY_ROUTES } from "./channel-availability-routes.js";
|
|
28
29
|
import { ROUTES as CHANNEL_READINESS_ROUTES } from "./channel-readiness-routes.js";
|
|
29
30
|
import { CHANNEL_ROUTES } from "./channel-route-definitions.js";
|
|
30
31
|
import { ROUTES as CHANNEL_VERIFICATION_ROUTES } from "./channel-verification-routes.js";
|
|
@@ -90,12 +91,14 @@ import { ROUTES as NOTIFICATION_ROUTES } from "./notification-routes.js";
|
|
|
90
91
|
import { ROUTES as OAUTH_APPS_ROUTES } from "./oauth-apps.js";
|
|
91
92
|
import { ROUTES as OAUTH_COMMANDS_ROUTES } from "./oauth-commands-routes.js";
|
|
92
93
|
import { ROUTES as OAUTH_CONNECT_ROUTES } from "./oauth-connect-routes.js";
|
|
94
|
+
import { ROUTES as OAUTH_LIFECYCLE_ROUTES } from "./oauth-lifecycle-routes.js";
|
|
93
95
|
import { ROUTES as OAUTH_PROVIDERS_ROUTES } from "./oauth-providers.js";
|
|
94
96
|
import { ROUTES as PLATFORM_ROUTES } from "./platform-routes.js";
|
|
95
97
|
import { ROUTES as PLAYGROUND_ROUTES } from "./playground/index.js";
|
|
96
98
|
import { ROUTES as PROFILER_ROUTES } from "./profiler-routes.js";
|
|
97
99
|
import { ROUTES as PS_ROUTES } from "./ps-routes.js";
|
|
98
100
|
import { ROUTES as PUBLISH_ROUTES } from "./publish-routes.js";
|
|
101
|
+
import { ROUTES as QUESTION_ROUTES } from "./question-routes.js";
|
|
99
102
|
import { ROUTES as RECORDING_ROUTES } from "./recording-routes.js";
|
|
100
103
|
import { ROUTES as RENAME_CONVERSATION_ROUTES } from "./rename-conversation-routes.js";
|
|
101
104
|
import { ROUTES as SCHEDULE_ROUTES } from "./schedule-routes.js";
|
|
@@ -144,6 +147,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
144
147
|
...CALL_ROUTES,
|
|
145
148
|
...CHANNEL_ROUTES,
|
|
146
149
|
...CHANNEL_VERIFICATION_ROUTES,
|
|
150
|
+
...CHANNEL_AVAILABILITY_ROUTES,
|
|
147
151
|
...CHANNEL_READINESS_ROUTES,
|
|
148
152
|
...BROWSER_ROUTES,
|
|
149
153
|
...BTW_ROUTES,
|
|
@@ -204,6 +208,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
204
208
|
...MIGRATION_ROUTES,
|
|
205
209
|
...NOTIFICATION_ROUTES,
|
|
206
210
|
...OAUTH_APPS_ROUTES,
|
|
211
|
+
...OAUTH_LIFECYCLE_ROUTES,
|
|
207
212
|
...OAUTH_COMMANDS_ROUTES,
|
|
208
213
|
...OAUTH_PROVIDERS_ROUTES,
|
|
209
214
|
...PLATFORM_ROUTES,
|
|
@@ -211,6 +216,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
211
216
|
...PROFILER_ROUTES,
|
|
212
217
|
...PS_ROUTES,
|
|
213
218
|
...PUBLISH_ROUTES,
|
|
219
|
+
...QUESTION_ROUTES,
|
|
214
220
|
...RECORDING_ROUTES,
|
|
215
221
|
...RENAME_CONVERSATION_ROUTES,
|
|
216
222
|
...SCHEDULE_ROUTES,
|
|
@@ -21,13 +21,9 @@ import {
|
|
|
21
21
|
setConversationInferenceProfileSession,
|
|
22
22
|
} from "../../memory/conversation-crud.js";
|
|
23
23
|
import { resolveConversationId } from "../../memory/conversation-key-store.js";
|
|
24
|
-
import {
|
|
25
|
-
import { buildAssistantEvent } from "../assistant-event.js";
|
|
26
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
24
|
+
import { publishConversationInferenceProfileChanged } from "../sync/resource-sync-events.js";
|
|
27
25
|
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
28
26
|
|
|
29
|
-
const log = getLogger("inference-profile-session-handler");
|
|
30
|
-
|
|
31
27
|
// ---------------------------------------------------------------------------
|
|
32
28
|
// Types
|
|
33
29
|
// ---------------------------------------------------------------------------
|
|
@@ -120,25 +116,12 @@ export async function setInferenceProfileSession({
|
|
|
120
116
|
};
|
|
121
117
|
}
|
|
122
118
|
setConversationInferenceProfileSession(resolvedId, null, null, null);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
profile: null,
|
|
130
|
-
sessionId: null,
|
|
131
|
-
expiresAt: null,
|
|
132
|
-
},
|
|
133
|
-
resolvedId,
|
|
134
|
-
),
|
|
135
|
-
)
|
|
136
|
-
.catch((err) => {
|
|
137
|
-
log.warn(
|
|
138
|
-
{ err, conversationId: resolvedId },
|
|
139
|
-
"Failed to publish conversation_inference_profile_updated event",
|
|
140
|
-
);
|
|
141
|
-
});
|
|
119
|
+
publishConversationInferenceProfileChanged({
|
|
120
|
+
conversationId: resolvedId,
|
|
121
|
+
profile: null,
|
|
122
|
+
sessionId: null,
|
|
123
|
+
expiresAt: null,
|
|
124
|
+
});
|
|
142
125
|
return {
|
|
143
126
|
conversationId: resolvedId,
|
|
144
127
|
profile: null,
|
|
@@ -201,25 +184,12 @@ export async function setInferenceProfileSession({
|
|
|
201
184
|
newExpiresAt ?? null,
|
|
202
185
|
);
|
|
203
186
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
profile,
|
|
211
|
-
sessionId: newSessionId ?? null,
|
|
212
|
-
expiresAt: newExpiresAt ?? null,
|
|
213
|
-
},
|
|
214
|
-
resolvedId,
|
|
215
|
-
),
|
|
216
|
-
)
|
|
217
|
-
.catch((err) => {
|
|
218
|
-
log.warn(
|
|
219
|
-
{ err, conversationId: resolvedId },
|
|
220
|
-
"Failed to publish conversation_inference_profile_updated event",
|
|
221
|
-
);
|
|
222
|
-
});
|
|
187
|
+
publishConversationInferenceProfileChanged({
|
|
188
|
+
conversationId: resolvedId,
|
|
189
|
+
profile,
|
|
190
|
+
sessionId: newSessionId ?? null,
|
|
191
|
+
expiresAt: newExpiresAt ?? null,
|
|
192
|
+
});
|
|
223
193
|
|
|
224
194
|
return {
|
|
225
195
|
conversationId: resolvedId,
|
|
@@ -307,6 +277,9 @@ export function listInferenceProfileSessionsWithRemaining(
|
|
|
307
277
|
}> {
|
|
308
278
|
return listActiveInferenceProfileSessions(conversationId).map((row) => ({
|
|
309
279
|
...row,
|
|
310
|
-
remainingSeconds: Math.max(
|
|
280
|
+
remainingSeconds: Math.max(
|
|
281
|
+
0,
|
|
282
|
+
Math.floor((row.expiresAt - Date.now()) / 1000),
|
|
283
|
+
),
|
|
311
284
|
}));
|
|
312
285
|
}
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { clearExpiredInferenceProfiles } from "../../memory/conversation-crud.js";
|
|
15
15
|
import { getLogger } from "../../util/logger.js";
|
|
16
|
-
import {
|
|
17
|
-
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
16
|
+
import { publishConversationInferenceProfileChanged } from "../sync/resource-sync-events.js";
|
|
18
17
|
|
|
19
18
|
const log = getLogger("inference-profile-session-reaper");
|
|
20
19
|
|
|
@@ -38,25 +37,12 @@ export function tickInferenceProfileReaper(): void {
|
|
|
38
37
|
const now = Date.now();
|
|
39
38
|
const cleared = clearExpiredInferenceProfiles(now);
|
|
40
39
|
for (const { conversationId } of cleared) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
profile: null,
|
|
48
|
-
sessionId: null,
|
|
49
|
-
expiresAt: null,
|
|
50
|
-
},
|
|
51
|
-
conversationId,
|
|
52
|
-
),
|
|
53
|
-
)
|
|
54
|
-
.catch((err) => {
|
|
55
|
-
log.warn(
|
|
56
|
-
{ err, conversationId },
|
|
57
|
-
"Failed to publish inference profile expiry event",
|
|
58
|
-
);
|
|
59
|
-
});
|
|
40
|
+
publishConversationInferenceProfileChanged({
|
|
41
|
+
conversationId,
|
|
42
|
+
profile: null,
|
|
43
|
+
sessionId: null,
|
|
44
|
+
expiresAt: null,
|
|
45
|
+
});
|
|
60
46
|
}
|
|
61
47
|
if (cleared.length > 0) {
|
|
62
48
|
log.info(
|
|
@@ -12,7 +12,13 @@ import { z } from "zod";
|
|
|
12
12
|
|
|
13
13
|
import { getConfigReadOnly } from "../../config/loader.js";
|
|
14
14
|
import { getDb } from "../../memory/db-connection.js";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
AuthSchema,
|
|
17
|
+
ConnectionProviderSchema,
|
|
18
|
+
ConnectionStatusSchema,
|
|
19
|
+
ProviderConnectionSchema,
|
|
20
|
+
VALID_CONNECTION_PROVIDERS,
|
|
21
|
+
} from "../../providers/inference/auth.js";
|
|
16
22
|
import {
|
|
17
23
|
createConnection,
|
|
18
24
|
deleteConnection,
|
|
@@ -21,11 +27,7 @@ import {
|
|
|
21
27
|
MANAGED_CONNECTION_NAMES,
|
|
22
28
|
updateConnection,
|
|
23
29
|
} from "../../providers/inference/connections.js";
|
|
24
|
-
import {
|
|
25
|
-
BadRequestError,
|
|
26
|
-
ConflictError,
|
|
27
|
-
NotFoundError,
|
|
28
|
-
} from "./errors.js";
|
|
30
|
+
import { BadRequestError, ConflictError, NotFoundError } from "./errors.js";
|
|
29
31
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
30
32
|
|
|
31
33
|
// ---------------------------------------------------------------------------
|
|
@@ -40,7 +42,10 @@ const providerConnectionResponseSchema = ProviderConnectionSchema;
|
|
|
40
42
|
|
|
41
43
|
function handleListConnections({ queryParams = {} }: RouteHandlerArgs) {
|
|
42
44
|
const provider = queryParams.provider;
|
|
43
|
-
const connections = listConnections(
|
|
45
|
+
const connections = listConnections(
|
|
46
|
+
getDb(),
|
|
47
|
+
provider ? { provider } : undefined,
|
|
48
|
+
);
|
|
44
49
|
return { connections };
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -75,14 +80,23 @@ function handleCreateConnection({ body = {} }: RouteHandlerArgs) {
|
|
|
75
80
|
throw new BadRequestError(`Invalid auth: ${authResult.error.message}`);
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
const statusResult =
|
|
83
|
+
const statusResult =
|
|
84
|
+
body.status !== undefined
|
|
85
|
+
? ConnectionStatusSchema.safeParse(body.status)
|
|
86
|
+
: null;
|
|
79
87
|
if (statusResult && !statusResult.success) {
|
|
80
88
|
throw new BadRequestError(`Invalid status: must be "active" or "disabled"`);
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
const labelRaw = body.label;
|
|
84
|
-
if (
|
|
85
|
-
|
|
92
|
+
if (
|
|
93
|
+
labelRaw !== undefined &&
|
|
94
|
+
labelRaw !== null &&
|
|
95
|
+
(typeof labelRaw !== "string" || labelRaw.length === 0)
|
|
96
|
+
) {
|
|
97
|
+
throw new BadRequestError(
|
|
98
|
+
`Invalid label: must be a non-empty string or null`,
|
|
99
|
+
);
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
const result = createConnection(getDb(), {
|
|
@@ -110,7 +124,10 @@ function handleCreateConnection({ body = {} }: RouteHandlerArgs) {
|
|
|
110
124
|
return result.connection;
|
|
111
125
|
}
|
|
112
126
|
|
|
113
|
-
function handleUpdateConnection({
|
|
127
|
+
function handleUpdateConnection({
|
|
128
|
+
pathParams = {},
|
|
129
|
+
body = {},
|
|
130
|
+
}: RouteHandlerArgs) {
|
|
114
131
|
const { name } = pathParams;
|
|
115
132
|
if (!name) throw new BadRequestError("name is required");
|
|
116
133
|
|
|
@@ -120,21 +137,33 @@ function handleUpdateConnection({ pathParams = {}, body = {} }: RouteHandlerArgs
|
|
|
120
137
|
throw new BadRequestError(`Invalid auth: ${authResult.error.message}`);
|
|
121
138
|
}
|
|
122
139
|
|
|
123
|
-
const statusResult =
|
|
140
|
+
const statusResult =
|
|
141
|
+
body.status !== undefined
|
|
142
|
+
? ConnectionStatusSchema.safeParse(body.status)
|
|
143
|
+
: null;
|
|
124
144
|
if (statusResult && !statusResult.success) {
|
|
125
145
|
throw new BadRequestError(`Invalid status: must be "active" or "disabled"`);
|
|
126
146
|
}
|
|
127
147
|
|
|
128
148
|
const labelRaw = body.label;
|
|
129
|
-
if (
|
|
130
|
-
|
|
149
|
+
if (
|
|
150
|
+
labelRaw !== undefined &&
|
|
151
|
+
labelRaw !== null &&
|
|
152
|
+
(typeof labelRaw !== "string" || labelRaw.length === 0)
|
|
153
|
+
) {
|
|
154
|
+
throw new BadRequestError(
|
|
155
|
+
`Invalid label: must be a non-empty string or null`,
|
|
156
|
+
);
|
|
131
157
|
}
|
|
132
158
|
|
|
133
159
|
// Managed connections: lock auth to `{type:"platform"}`. The boot upsert in
|
|
134
160
|
// `seedCanonicalConnections` would revert any other value on next restart;
|
|
135
161
|
// reject the write here so the surprise loop never happens. Label and status
|
|
136
162
|
// remain user-editable (the boot upsert leaves those alone).
|
|
137
|
-
if (
|
|
163
|
+
if (
|
|
164
|
+
MANAGED_CONNECTION_NAMES.has(name) &&
|
|
165
|
+
authResult.data.type !== "platform"
|
|
166
|
+
) {
|
|
138
167
|
throw new BadRequestError(
|
|
139
168
|
`Cannot change auth on managed connection "${name}". Auth is locked to platform.`,
|
|
140
169
|
);
|
|
@@ -180,7 +209,10 @@ function handleDeleteConnection({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
180
209
|
const config = getConfigReadOnly();
|
|
181
210
|
|
|
182
211
|
// llm.default carries provider_connection (LLMConfigBase).
|
|
183
|
-
if (
|
|
212
|
+
if (
|
|
213
|
+
(config.llm?.default as Record<string, unknown> | undefined)
|
|
214
|
+
?.provider_connection === name
|
|
215
|
+
) {
|
|
184
216
|
throw new ConflictError(
|
|
185
217
|
`Connection "${name}" is referenced by llm.default. Update llm.default.provider_connection before deleting.`,
|
|
186
218
|
{ referencedBy: ["llm.default"] },
|
|
@@ -190,7 +222,9 @@ function handleDeleteConnection({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
190
222
|
// llm.profiles.*: only ProfileEntry has provider_connection.
|
|
191
223
|
const profiles = config.llm?.profiles ?? {};
|
|
192
224
|
const referencingProfiles = Object.entries(profiles)
|
|
193
|
-
.filter(
|
|
225
|
+
.filter(
|
|
226
|
+
([, p]) => (p as Record<string, unknown>).provider_connection === name,
|
|
227
|
+
)
|
|
194
228
|
.map(([profileName]) => profileName);
|
|
195
229
|
|
|
196
230
|
const result = deleteConnection(getDb(), name, {
|
|
@@ -234,7 +268,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
234
268
|
description: `Filter by provider. One of: ${VALID_CONNECTION_PROVIDERS.join(", ")}`,
|
|
235
269
|
},
|
|
236
270
|
],
|
|
237
|
-
responseBody: z.object({
|
|
271
|
+
responseBody: z.object({
|
|
272
|
+
connections: z.array(providerConnectionResponseSchema),
|
|
273
|
+
}),
|
|
238
274
|
handler: handleListConnections,
|
|
239
275
|
},
|
|
240
276
|
{
|
|
@@ -291,7 +327,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
291
327
|
}),
|
|
292
328
|
responseBody: providerConnectionResponseSchema,
|
|
293
329
|
additionalResponses: {
|
|
294
|
-
"400": {
|
|
330
|
+
"400": {
|
|
331
|
+
description:
|
|
332
|
+
"Invalid auth schema, or attempt to change auth on a managed connection",
|
|
333
|
+
},
|
|
295
334
|
"404": { description: "Connection not found" },
|
|
296
335
|
},
|
|
297
336
|
handler: handleUpdateConnection,
|
|
@@ -308,9 +347,14 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
308
347
|
pathParams: [{ name: "name", description: "Connection name" }],
|
|
309
348
|
responseBody: z.object({ ok: z.literal(true) }),
|
|
310
349
|
additionalResponses: {
|
|
311
|
-
"400": {
|
|
350
|
+
"400": {
|
|
351
|
+
description:
|
|
352
|
+
"Connection is a Vellum-managed connection and cannot be deleted",
|
|
353
|
+
},
|
|
312
354
|
"404": { description: "Connection not found" },
|
|
313
|
-
"409": {
|
|
355
|
+
"409": {
|
|
356
|
+
description: "Connection is referenced by profile(s) or call site(s)",
|
|
357
|
+
},
|
|
314
358
|
},
|
|
315
359
|
handler: handleDeleteConnection,
|
|
316
360
|
},
|
|
@@ -12,9 +12,6 @@ import {
|
|
|
12
12
|
userInfo,
|
|
13
13
|
} from "../../../../messaging/providers/slack/client.js";
|
|
14
14
|
import type { SlackConversation } from "../../../../messaging/providers/slack/types.js";
|
|
15
|
-
import { getConnectionByProvider } from "../../../../oauth/oauth-store.js";
|
|
16
|
-
import { credentialKey } from "../../../../security/credential-key.js";
|
|
17
|
-
import { getSecureKeyAsync } from "../../../../security/secure-keys.js";
|
|
18
15
|
import { getLogger } from "../../../../util/logger.js";
|
|
19
16
|
import {
|
|
20
17
|
BadRequestError,
|
|
@@ -23,50 +20,10 @@ import {
|
|
|
23
20
|
ServiceUnavailableError,
|
|
24
21
|
} from "../../errors.js";
|
|
25
22
|
import type { RouteDefinition, RouteHandlerArgs } from "../../types.js";
|
|
23
|
+
import { resolveSlackToken } from "./token.js";
|
|
26
24
|
|
|
27
25
|
const log = getLogger("slack-share");
|
|
28
26
|
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// Shared helpers
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Resolve a Slack token for the Share UI, mirroring the read/write auth split
|
|
35
|
-
* in `messaging/providers/slack/adapter.ts`.
|
|
36
|
-
*
|
|
37
|
-
* For Socket Mode installs (tokens stored under `credential/slack_channel/*`),
|
|
38
|
-
* prefer the user OAuth token (xoxp-) for reads when present — this lets the
|
|
39
|
-
* channel picker surface channels the user belongs to but the bot doesn't.
|
|
40
|
-
* Fall back to the bot token (xoxb-) otherwise.
|
|
41
|
-
*
|
|
42
|
-
* Writes MUST always use the bot token so posted messages come from the bot
|
|
43
|
-
* identity, never the user. Passing `user_token` to chat.postMessage would
|
|
44
|
-
* post as the user — unambiguously wrong for Share UI behavior.
|
|
45
|
-
*
|
|
46
|
-
* For legacy OAuth installs (no Socket Mode tokens), fall back to the OAuth
|
|
47
|
-
* connection's access_token, which is the bot token in Slack's OAuth v2 flow.
|
|
48
|
-
*/
|
|
49
|
-
async function resolveSlackToken(
|
|
50
|
-
mode: "read" | "write",
|
|
51
|
-
): Promise<string | undefined> {
|
|
52
|
-
const botToken = await getSecureKeyAsync(
|
|
53
|
-
credentialKey("slack_channel", "bot_token"),
|
|
54
|
-
);
|
|
55
|
-
if (botToken) {
|
|
56
|
-
if (mode === "read") {
|
|
57
|
-
const userToken = await getSecureKeyAsync(
|
|
58
|
-
credentialKey("slack_channel", "user_token"),
|
|
59
|
-
);
|
|
60
|
-
return userToken ?? botToken;
|
|
61
|
-
}
|
|
62
|
-
return botToken;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const conn = getConnectionByProvider("slack");
|
|
66
|
-
if (!conn) return undefined;
|
|
67
|
-
return await getSecureKeyAsync(`oauth_connection/${conn.id}/access_token`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
27
|
// ---------------------------------------------------------------------------
|
|
71
28
|
// GET /v1/slack/channels
|
|
72
29
|
// ---------------------------------------------------------------------------
|
|
@@ -179,15 +136,11 @@ export async function handleShareToSlackChannel({
|
|
|
179
136
|
};
|
|
180
137
|
|
|
181
138
|
if (!appId || !channelId) {
|
|
182
|
-
throw new BadRequestError(
|
|
183
|
-
"Missing required fields: appId, channelId",
|
|
184
|
-
);
|
|
139
|
+
throw new BadRequestError("Missing required fields: appId, channelId");
|
|
185
140
|
}
|
|
186
141
|
|
|
187
142
|
if (typeof appId !== "string" || typeof channelId !== "string") {
|
|
188
|
-
throw new BadRequestError(
|
|
189
|
-
"Fields appId and channelId must be strings",
|
|
190
|
-
);
|
|
143
|
+
throw new BadRequestError("Fields appId and channelId must be strings");
|
|
191
144
|
}
|
|
192
145
|
|
|
193
146
|
if (message !== undefined && typeof message !== "string") {
|
|
@@ -245,8 +198,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
245
198
|
endpoint: "slack/channels",
|
|
246
199
|
method: "GET",
|
|
247
200
|
summary: "List Slack channels",
|
|
248
|
-
description:
|
|
249
|
-
"List Slack channels, groups, and DMs for the channel picker.",
|
|
201
|
+
description: "List Slack channels, groups, and DMs for the channel picker.",
|
|
250
202
|
tags: ["integrations"],
|
|
251
203
|
requirePolicyEnforcement: true,
|
|
252
204
|
handler: () => handleListSlackChannels(),
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Slack token resolver.
|
|
3
|
+
*
|
|
4
|
+
* Resolve a Slack token for the Share UI, mirroring the read/write auth split
|
|
5
|
+
* in `messaging/providers/slack/adapter.ts`.
|
|
6
|
+
*
|
|
7
|
+
* For Socket Mode installs (tokens stored under `credential/slack_channel/*`),
|
|
8
|
+
* prefer the user OAuth token (xoxp-) for reads when present — this lets the
|
|
9
|
+
* channel picker surface channels the user belongs to but the bot doesn't.
|
|
10
|
+
* Fall back to the bot token (xoxb-) otherwise.
|
|
11
|
+
*
|
|
12
|
+
* Writes MUST always use the bot token so posted messages come from the bot
|
|
13
|
+
* identity, never the user. Passing `user_token` to chat.postMessage would
|
|
14
|
+
* post as the user — unambiguously wrong for Share UI behavior.
|
|
15
|
+
*
|
|
16
|
+
* For legacy OAuth installs (no Socket Mode tokens), fall back to the OAuth
|
|
17
|
+
* connection's access_token, which is the bot token in Slack's OAuth v2 flow.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { getConnectionByProvider } from "../../../../oauth/oauth-store.js";
|
|
21
|
+
import { credentialKey } from "../../../../security/credential-key.js";
|
|
22
|
+
import { getSecureKeyAsync } from "../../../../security/secure-keys.js";
|
|
23
|
+
|
|
24
|
+
export async function resolveSlackToken(
|
|
25
|
+
mode: "read" | "write",
|
|
26
|
+
): Promise<string | undefined> {
|
|
27
|
+
const botToken = await getSecureKeyAsync(
|
|
28
|
+
credentialKey("slack_channel", "bot_token"),
|
|
29
|
+
);
|
|
30
|
+
if (botToken) {
|
|
31
|
+
if (mode === "read") {
|
|
32
|
+
const userToken = await getSecureKeyAsync(
|
|
33
|
+
credentialKey("slack_channel", "user_token"),
|
|
34
|
+
);
|
|
35
|
+
return userToken ?? botToken;
|
|
36
|
+
}
|
|
37
|
+
return botToken;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const conn = getConnectionByProvider("slack");
|
|
41
|
+
if (!conn) return undefined;
|
|
42
|
+
return await getSecureKeyAsync(`oauth_connection/${conn.id}/access_token`);
|
|
43
|
+
}
|
|
@@ -95,8 +95,7 @@ export async function handleSetTwilioCredentials({
|
|
|
95
95
|
|
|
96
96
|
// Validate credentials against Twilio API
|
|
97
97
|
const authHeader =
|
|
98
|
-
"Basic " +
|
|
99
|
-
Buffer.from(`${accountSid}:${authToken}`).toString("base64");
|
|
98
|
+
"Basic " + Buffer.from(`${accountSid}:${authToken}`).toString("base64");
|
|
100
99
|
try {
|
|
101
100
|
const res = await fetch(
|
|
102
101
|
`https://api.twilio.com/2010-04-01/Accounts/${accountSid}.json`,
|
|
@@ -121,9 +120,7 @@ export async function handleSetTwilioCredentials({
|
|
|
121
120
|
accountSid,
|
|
122
121
|
);
|
|
123
122
|
if (!sidStored) {
|
|
124
|
-
throw new InternalError(
|
|
125
|
-
"Failed to store Account SID in secure storage",
|
|
126
|
-
);
|
|
123
|
+
throw new InternalError("Failed to store Account SID in secure storage");
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
const tokenStored = await setSecureKeyAsync(
|
|
@@ -132,14 +129,13 @@ export async function handleSetTwilioCredentials({
|
|
|
132
129
|
);
|
|
133
130
|
if (!tokenStored) {
|
|
134
131
|
await deleteSecureKeyAsync(credentialKey("twilio", "account_sid"));
|
|
135
|
-
throw new InternalError(
|
|
136
|
-
"Failed to store Auth Token in secure storage",
|
|
137
|
-
);
|
|
132
|
+
throw new InternalError("Failed to store Auth Token in secure storage");
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
const raw = loadRawConfig();
|
|
141
136
|
const twilio = (raw?.twilio ?? {}) as Record<string, unknown>;
|
|
142
137
|
twilio.accountSid = accountSid;
|
|
138
|
+
twilio.setupStarted = true;
|
|
143
139
|
saveRawConfig({ ...raw, twilio });
|
|
144
140
|
|
|
145
141
|
upsertCredentialMetadata("twilio", "account_sid", {
|
|
@@ -210,9 +206,7 @@ async function handleListTwilioNumbers() {
|
|
|
210
206
|
return { success: true, hasCredentials: true, numbers };
|
|
211
207
|
}
|
|
212
208
|
|
|
213
|
-
export async function handleProvisionTwilioNumber({
|
|
214
|
-
body,
|
|
215
|
-
}: RouteHandlerArgs) {
|
|
209
|
+
export async function handleProvisionTwilioNumber({ body }: RouteHandlerArgs) {
|
|
216
210
|
if (!(await hasTwilioCredentials())) {
|
|
217
211
|
throw new BadRequestError(
|
|
218
212
|
"Twilio credentials not configured. Set credentials first.",
|
|
@@ -323,8 +317,7 @@ async function handleReleaseTwilioNumber({ body }: RouteHandlerArgs) {
|
|
|
323
317
|
};
|
|
324
318
|
const raw = loadRawConfig();
|
|
325
319
|
const twilio = (raw?.twilio ?? {}) as Record<string, unknown>;
|
|
326
|
-
const phoneNumber =
|
|
327
|
-
requestedNumber || (twilio.phoneNumber as string) || "";
|
|
320
|
+
const phoneNumber = requestedNumber || (twilio.phoneNumber as string) || "";
|
|
328
321
|
|
|
329
322
|
if (!phoneNumber) {
|
|
330
323
|
throw new BadRequestError(
|
|
@@ -52,7 +52,7 @@ function handleNotificationIntentResult({ body = {} }: RouteHandlerArgs) {
|
|
|
52
52
|
|
|
53
53
|
const AttentionHintsSchema = z.object({
|
|
54
54
|
requiresAction: z.boolean(),
|
|
55
|
-
urgency: z.enum(["low", "medium", "high"]),
|
|
55
|
+
urgency: z.enum(["low", "medium", "high", "critical"]),
|
|
56
56
|
deadlineAt: z.number().optional(),
|
|
57
57
|
isAsyncBackground: z.boolean(),
|
|
58
58
|
visibleInSourceNow: z.boolean(),
|