@vellumai/assistant 0.8.1 → 0.8.3
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 +13 -19
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +17 -0
- package/docker-init-apt-root.sh +167 -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 +642 -5
- 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-loop-exit-reason.test.ts +272 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- 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 +147 -0
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- 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 +31 -65
- 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 +59 -1
- 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-media-retry.test.ts +19 -8
- 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 +102 -13
- 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__/date-context.test.ts +45 -0
- 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 +151 -55
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- 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 +507 -10
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- 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-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +15 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +99 -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-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +58 -13
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +36 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-resolver.test.ts +255 -2
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +41 -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__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -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 +242 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- 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} +7 -2
- 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 +158 -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} +33 -31
- 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__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +1 -1
- 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 +670 -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-087-memory-router-balanced-profile.test.ts +228 -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/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/agent/loop.ts +167 -18
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +122 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +960 -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 +388 -346
- package/src/cli/commands/plugins.ts +252 -0
- package/src/cli/commands/schedules.ts +683 -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__/search-plugins.test.ts +261 -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 +303 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +52 -2
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +140 -22
- 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/phone-calls/SKILL.md +1 -1
- 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/call-site-defaults.ts +105 -0
- package/src/config/feature-flag-registry.json +41 -9
- package/src/config/llm-resolver.ts +52 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +9 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
- package/src/config/schemas/channels.ts +17 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +23 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +4 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1107 -0
- package/src/context/token-estimator.ts +34 -36
- 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 +33 -18
- 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-handlers.ts +78 -0
- package/src/daemon/conversation-agent-loop.ts +198 -11
- 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 +25 -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 -8
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +289 -0
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/conversations.ts +1 -0
- 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 +153 -27
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/lifecycle.ts +89 -91
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +85 -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/notifications.ts +21 -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 +11 -54
- package/src/daemon/pkb-reminder-builder.ts +5 -20
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +24 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +33 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +135 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +73 -189
- package/src/home/__tests__/feed-types.test.ts +80 -0
- package/src/home/feed-types.ts +36 -2
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/ipc/cli-client.ts +147 -45
- 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 +483 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
- 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 +197 -11
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +12 -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 +150 -12
- package/src/memory/graph/conversation-graph-memory.ts +49 -21
- package/src/memory/graph/tools.ts +9 -40
- package/src/memory/indexer.ts +34 -29
- package/src/memory/invite-store.ts +53 -0
- 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 +24 -12
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-enqueue.ts +1 -20
- package/src/memory/memory-retrospective-job.ts +33 -6
- 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/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/index.ts +9 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +3 -3
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection.test.ts +288 -11
- 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/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection.ts +81 -26
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +63 -8
- 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/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +11 -2
- 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/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +113 -45
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +21 -1
- package/src/notifications/home-feed-side-effect.ts +138 -5
- package/src/notifications/signal.ts +3 -5
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +19 -6
- 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 +74 -22
- 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 +187 -42
- 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 +40 -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 +10 -43
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +95 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -174
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +164 -0
- package/src/providers/__tests__/inference.test.ts +24 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +68 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +32 -6
- package/src/providers/inference/auth.ts +12 -0
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/connections.ts +159 -34
- package/src/providers/inference/resolve-auth.ts +14 -4
- package/src/providers/model-catalog.ts +249 -12
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +169 -8
- package/src/providers/openrouter/client.ts +49 -4
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -2
- 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 +38 -0
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +52 -15
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +103 -15
- package/src/runtime/auth/route-policy.ts +21 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +19 -47
- 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__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +172 -23
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- 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 +126 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -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 +99 -35
- package/src/runtime/routes/conversation-routes.ts +97 -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 +8 -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 +199 -22
- package/src/runtime/routes/integrations/a2a.ts +235 -0
- 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/llm-call-sites-routes.ts +11 -1
- 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 +98 -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 +17 -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/memory/register.ts +1 -9
- 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 +107 -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/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/registry.ts +10 -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/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import {
|
|
14
14
|
type FeedItem,
|
|
15
|
+
type FeedItemCategory,
|
|
16
|
+
type FeedItemDetailPanelKind,
|
|
15
17
|
feedItemSchema,
|
|
16
18
|
type FeedItemUrgency,
|
|
17
19
|
} from "../home/feed-types.js";
|
|
@@ -23,6 +25,7 @@ import type { NotificationSignal } from "./signal.js";
|
|
|
23
25
|
import type {
|
|
24
26
|
NotificationDecision,
|
|
25
27
|
NotificationDeliveryResult,
|
|
28
|
+
RenderedChannelCopy,
|
|
26
29
|
} from "./types.js";
|
|
27
30
|
|
|
28
31
|
const log = getLogger("home-feed-side-effect");
|
|
@@ -49,9 +52,30 @@ export async function writeHomeFeedItemForSignal(
|
|
|
49
52
|
): Promise<FeedItem | null> {
|
|
50
53
|
if (!shouldMirrorToHomeFeed(signal)) return null;
|
|
51
54
|
|
|
52
|
-
const renderedCopy =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
const renderedCopy =
|
|
56
|
+
decision.renderedCopy.vellum ??
|
|
57
|
+
firstSelectedRenderedCopy(decision.renderedCopy, decision.selectedChannels);
|
|
58
|
+
const payloadTitle =
|
|
59
|
+
readPayloadString(signal.contextPayload, "title") ??
|
|
60
|
+
readPayloadString(signal.contextPayload, "requestedTitle");
|
|
61
|
+
const payloadBody =
|
|
62
|
+
readPayloadString(signal.contextPayload, "body") ??
|
|
63
|
+
readPayloadString(signal.contextPayload, "requestedMessage");
|
|
64
|
+
|
|
65
|
+
// Source the title from the payload only. The LLM's `renderedCopy.title`
|
|
66
|
+
// often echoes the body when no explicit title was passed, which stutters
|
|
67
|
+
// against `summary` in the row. Leave undefined when absent; renderers
|
|
68
|
+
// fall back to `summary`.
|
|
69
|
+
const resolvedTitle = payloadTitle?.trim() || undefined;
|
|
70
|
+
const resolvedSummary =
|
|
71
|
+
renderedCopy?.body?.trim() || payloadBody?.trim() || "";
|
|
72
|
+
if (!resolvedSummary) {
|
|
73
|
+
log.warn(
|
|
74
|
+
{ signalId: signal.signalId, sourceEventName: signal.sourceEventName },
|
|
75
|
+
"Home-feed write skipped: no summary available (would have fallen back to event name)",
|
|
76
|
+
);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
55
79
|
|
|
56
80
|
const conversationId = deliveryResults.find(
|
|
57
81
|
(r) => r.channel === "vellum",
|
|
@@ -61,17 +85,31 @@ export async function writeHomeFeedItemForSignal(
|
|
|
61
85
|
: undefined;
|
|
62
86
|
const now = new Date().toISOString();
|
|
63
87
|
|
|
88
|
+
const category = deriveCategory(signal);
|
|
89
|
+
const panelKind = deriveDetailPanelKind(signal);
|
|
90
|
+
const metadata =
|
|
91
|
+
signal.contextPayload &&
|
|
92
|
+
typeof signal.contextPayload === "object" &&
|
|
93
|
+
!Array.isArray(signal.contextPayload)
|
|
94
|
+
? (signal.contextPayload as Record<string, unknown>)
|
|
95
|
+
: undefined;
|
|
96
|
+
|
|
64
97
|
const item: FeedItem = {
|
|
65
98
|
id: `notif:${signal.signalId}`,
|
|
66
99
|
type: "notification",
|
|
67
100
|
priority: 50,
|
|
68
|
-
title:
|
|
69
|
-
summary:
|
|
101
|
+
...(resolvedTitle ? { title: resolvedTitle } : {}),
|
|
102
|
+
summary: resolvedSummary,
|
|
70
103
|
timestamp: now,
|
|
71
104
|
createdAt: now,
|
|
72
105
|
status: "new",
|
|
106
|
+
category,
|
|
107
|
+
noteworthy: deriveNoteworthy(signal),
|
|
108
|
+
fromAssistant: signal.sourceChannel === "assistant_tool",
|
|
73
109
|
...(urgency ? { urgency } : {}),
|
|
74
110
|
...(conversationId ? { conversationId } : {}),
|
|
111
|
+
...(panelKind ? { detailPanel: { kind: panelKind } } : {}),
|
|
112
|
+
...(metadata ? { metadata } : {}),
|
|
75
113
|
};
|
|
76
114
|
|
|
77
115
|
try {
|
|
@@ -88,12 +126,60 @@ export async function writeHomeFeedItemForSignal(
|
|
|
88
126
|
return item;
|
|
89
127
|
}
|
|
90
128
|
|
|
129
|
+
// ── Category & detail-panel derivation ────────────────────────────────
|
|
130
|
+
|
|
131
|
+
const EVENT_CATEGORY_MAP: Record<string, FeedItemCategory> = {
|
|
132
|
+
"credential.health_alert": "security",
|
|
133
|
+
"activity.failed": "background",
|
|
134
|
+
"activity.complete": "background",
|
|
135
|
+
"watcher.notification": "system",
|
|
136
|
+
"schedule.notify": "scheduling",
|
|
137
|
+
"guardian.question": "security",
|
|
138
|
+
"guardian.channel_activation": "security",
|
|
139
|
+
"ingress.access_request": "security",
|
|
140
|
+
"ingress.escalation": "security",
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
function deriveCategory(signal: NotificationSignal): FeedItemCategory {
|
|
144
|
+
return EVENT_CATEGORY_MAP[signal.sourceEventName] ?? "system";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function deriveDetailPanelKind(
|
|
148
|
+
signal: NotificationSignal,
|
|
149
|
+
): FeedItemDetailPanelKind | undefined {
|
|
150
|
+
if (signal.sourceEventName === "credential.health_alert") {
|
|
151
|
+
return "toolPermission";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (signal.sourceEventName === "guardian.question") {
|
|
155
|
+
const payload = signal.contextPayload;
|
|
156
|
+
const kind =
|
|
157
|
+
payload && typeof payload === "object" && "requestKind" in payload
|
|
158
|
+
? (payload as Record<string, unknown>).requestKind
|
|
159
|
+
: undefined;
|
|
160
|
+
if (kind === "tool_approval" || kind === "tool_grant_request") {
|
|
161
|
+
return "permissionChat";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
91
168
|
/**
|
|
92
169
|
* `sourceContextId` is best-effort — it may not be a conversation id
|
|
93
170
|
* (e.g. scheduler job id, watcher event id), so a lookup failure
|
|
94
171
|
* falls through to "not a background conversation" rather than throwing.
|
|
172
|
+
*
|
|
173
|
+
* `assistant_tool` is the source channel used by the `notifications send`
|
|
174
|
+
* skill (and by background-job failure emits). These signals represent
|
|
175
|
+
* the assistant actively choosing to share, so we mirror them into the
|
|
176
|
+
* home feed without requiring a background-typed conversation or the
|
|
177
|
+
* `isAsyncBackground` hint — the documented (SKILL.md) CLI surface
|
|
178
|
+
* intentionally does not expose either; internal call sites that still set
|
|
179
|
+
* the hint keep working unchanged.
|
|
95
180
|
*/
|
|
96
181
|
function shouldMirrorToHomeFeed(signal: NotificationSignal): boolean {
|
|
182
|
+
if (signal.sourceChannel === "assistant_tool") return true;
|
|
97
183
|
if (signal.attentionHints.isAsyncBackground) return true;
|
|
98
184
|
if (!signal.sourceContextId) return false;
|
|
99
185
|
try {
|
|
@@ -109,3 +195,50 @@ function readPayloadString(payload: unknown, key: string): string | undefined {
|
|
|
109
195
|
const value = (payload as Record<string, unknown>)[key];
|
|
110
196
|
return typeof value === "string" ? value : undefined;
|
|
111
197
|
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Routing-intent enforcement can prune `selectedChannels` without also
|
|
201
|
+
* pruning `renderedCopy`, so iterating `renderedCopy` directly risks
|
|
202
|
+
* surfacing copy for a channel that was never delivered. Walk
|
|
203
|
+
* `selectedChannels` in order instead so the channel that actually shipped
|
|
204
|
+
* wins.
|
|
205
|
+
*/
|
|
206
|
+
function firstSelectedRenderedCopy(
|
|
207
|
+
renderedCopy: NotificationDecision["renderedCopy"],
|
|
208
|
+
selectedChannels: NotificationDecision["selectedChannels"],
|
|
209
|
+
): RenderedChannelCopy | undefined {
|
|
210
|
+
for (const channel of selectedChannels) {
|
|
211
|
+
const copy = renderedCopy[channel];
|
|
212
|
+
if (copy && (copy.title?.trim() || copy.body?.trim())) return copy;
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── Noteworthy derivation ─────────────────────────────────────────────
|
|
218
|
+
//
|
|
219
|
+
// Clients split the feed into inbox-style (noteworthy) and activity-style
|
|
220
|
+
// (routine) surfaces. Assistant-initiated shares and a small allow-list of
|
|
221
|
+
// high-importance system events land in the inbox; routine background
|
|
222
|
+
// signals stay in activity.
|
|
223
|
+
|
|
224
|
+
const NOTEWORTHY_EVENT_NAMES: ReadonlySet<string> = new Set([
|
|
225
|
+
"guardian.question",
|
|
226
|
+
"guardian.channel_activation",
|
|
227
|
+
"ingress.access_request",
|
|
228
|
+
"ingress.escalation",
|
|
229
|
+
"credential.health_alert",
|
|
230
|
+
]);
|
|
231
|
+
|
|
232
|
+
function deriveNoteworthy(signal: NotificationSignal): boolean {
|
|
233
|
+
// Background-job failures emit with `sourceChannel: "assistant_tool"`
|
|
234
|
+
// (see `runtime/background-job-runner.ts`), so the activity.failed rule
|
|
235
|
+
// must run BEFORE the assistant_tool short-circuit — otherwise every
|
|
236
|
+
// routine watcher/heartbeat failure would land in the Inbox instead of
|
|
237
|
+
// staying in the activity feed.
|
|
238
|
+
if (signal.sourceEventName === "activity.failed") {
|
|
239
|
+
return signal.attentionHints.urgency === "critical";
|
|
240
|
+
}
|
|
241
|
+
if (signal.sourceChannel === "assistant_tool") return true;
|
|
242
|
+
if (NOTEWORTHY_EVENT_NAMES.has(signal.sourceEventName)) return true;
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* decision engine route contextually.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { ConversationCreateType } from "../memory/conversation-crud.js";
|
|
7
8
|
import type { GuardianQuestionPayload } from "./guardian-question-mode.js";
|
|
8
9
|
|
|
9
10
|
// ── Source channel registry ────────────────────────────────────────────
|
|
@@ -106,10 +107,6 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
|
|
|
106
107
|
description:
|
|
107
108
|
"OAuth credential health issue detected (expired, revoked, missing scopes)",
|
|
108
109
|
},
|
|
109
|
-
{
|
|
110
|
-
id: "heartbeat.alert",
|
|
111
|
-
description: "Heartbeat found something worth surfacing to the guardian",
|
|
112
|
-
},
|
|
113
110
|
] as const;
|
|
114
111
|
|
|
115
112
|
export type NotificationSourceEventName =
|
|
@@ -119,7 +116,7 @@ export type NotificationSourceEventName =
|
|
|
119
116
|
|
|
120
117
|
export interface AttentionHints {
|
|
121
118
|
requiresAction: boolean;
|
|
122
|
-
urgency: "low" | "medium" | "high";
|
|
119
|
+
urgency: "low" | "medium" | "high" | "critical";
|
|
123
120
|
deadlineAt?: number; // epoch ms
|
|
124
121
|
isAsyncBackground: boolean;
|
|
125
122
|
visibleInSourceNow: boolean;
|
|
@@ -214,5 +211,6 @@ export interface NotificationSignal<TEventName extends string = string> {
|
|
|
214
211
|
groupId?: string;
|
|
215
212
|
scheduleJobId?: string;
|
|
216
213
|
source?: string;
|
|
214
|
+
conversationType?: ConversationCreateType;
|
|
217
215
|
};
|
|
218
216
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import type { ChannelPolicies } from "../channels/config.js";
|
|
9
9
|
import type { ChannelId } from "../channels/types.js";
|
|
10
|
+
import type { AttentionHints } from "./signal.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Derived from the channel policy registry: only channels whose
|
|
@@ -81,6 +82,13 @@ export interface ChannelDeliveryPayload {
|
|
|
81
82
|
deepLinkTarget?: Record<string, unknown>;
|
|
82
83
|
/** Original signal context payload — available for channel-specific structured rendering. */
|
|
83
84
|
contextPayload?: Record<string, unknown>;
|
|
85
|
+
/**
|
|
86
|
+
* Forwarded from the originating signal so adapters can make
|
|
87
|
+
* urgency-aware decisions (e.g. the vellum adapter suppresses the OS
|
|
88
|
+
* banner for non-urgent intents while still emitting the conversation
|
|
89
|
+
* pairing side effects).
|
|
90
|
+
*/
|
|
91
|
+
urgency: AttentionHints["urgency"];
|
|
84
92
|
}
|
|
85
93
|
|
|
86
94
|
/** Interface that each channel adapter must implement. */
|
|
@@ -92,7 +92,7 @@ export async function resolveOAuthConnection(
|
|
|
92
92
|
? ` matching ${filters.join(" and ")}`
|
|
93
93
|
: "";
|
|
94
94
|
throw new Error(
|
|
95
|
-
`No active OAuth connection found for "${provider}"${qualifier}.
|
|
95
|
+
`No active OAuth connection found for "${provider}"${qualifier}. The ${provider} service needs to be connected before it can be used.`,
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -102,7 +102,7 @@ export async function resolveOAuthConnection(
|
|
|
102
102
|
});
|
|
103
103
|
if (!tokenResult.value) {
|
|
104
104
|
throw new Error(
|
|
105
|
-
`OAuth connection for "${provider}" exists but
|
|
105
|
+
`OAuth connection for "${provider}" exists but the access token is missing or expired. The ${provider} service needs to be reconnected.`,
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -223,18 +223,22 @@ async function resolvePlatformConnectionId(
|
|
|
223
223
|
|
|
224
224
|
if (connections.length === 0) {
|
|
225
225
|
throw new Error(
|
|
226
|
-
`No active
|
|
226
|
+
`No active OAuth connection found for provider "${provider}"` +
|
|
227
227
|
(account ? ` with account "${account}"` : "") +
|
|
228
|
-
|
|
228
|
+
`. The ${provider} service needs to be connected.`,
|
|
229
229
|
);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
if (connections.length > 1 && !account) {
|
|
233
|
+
const allAccounts = connections
|
|
234
|
+
.map((c) => c.account_label ?? c.id)
|
|
235
|
+
.join(", ");
|
|
233
236
|
log.warn(
|
|
234
237
|
{
|
|
235
238
|
provider,
|
|
236
239
|
count: connections.length,
|
|
237
240
|
selectedId: connections[0].id,
|
|
241
|
+
allAccounts,
|
|
238
242
|
},
|
|
239
243
|
"Multiple active platform connections found; using the most recently created. " +
|
|
240
244
|
"Pass an account option to select a specific connection.",
|
|
@@ -261,17 +261,57 @@ describe("PlatformOAuthConnection", () => {
|
|
|
261
261
|
).rejects.toThrow(CredentialRequiredError);
|
|
262
262
|
});
|
|
263
263
|
|
|
264
|
-
test("502 response throws ProviderUnreachableError", async () => {
|
|
264
|
+
test("502 response retries then throws ProviderUnreachableError", async () => {
|
|
265
|
+
let callCount = 0;
|
|
266
|
+
const client = makeMockClient(
|
|
267
|
+
mock(async () => {
|
|
268
|
+
callCount++;
|
|
269
|
+
return new Response("", { status: 502 });
|
|
270
|
+
}) as unknown as typeof globalThis.fetch,
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
|
|
274
|
+
await expect(
|
|
275
|
+
conn.request({ method: "GET", path: "/test" }),
|
|
276
|
+
).rejects.toThrow(ProviderUnreachableError);
|
|
277
|
+
// 1 initial + 3 retries = 4 total attempts
|
|
278
|
+
expect(callCount).toBe(4);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("502 response includes detail from response body", async () => {
|
|
265
282
|
const client = makeMockClient(
|
|
266
283
|
mock(
|
|
267
|
-
async () => new Response("", { status: 502 }),
|
|
284
|
+
async () => new Response("upstream timeout after 30s", { status: 502 }),
|
|
268
285
|
) as unknown as typeof globalThis.fetch,
|
|
269
286
|
);
|
|
270
287
|
|
|
271
288
|
const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
|
|
272
289
|
await expect(
|
|
273
290
|
conn.request({ method: "GET", path: "/test" }),
|
|
274
|
-
).rejects.toThrow(
|
|
291
|
+
).rejects.toThrow(/upstream timeout after 30s/);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("502 recovers on retry", async () => {
|
|
295
|
+
let callCount = 0;
|
|
296
|
+
const client = makeMockClient(
|
|
297
|
+
mock(async () => {
|
|
298
|
+
callCount++;
|
|
299
|
+
if (callCount <= 2) {
|
|
300
|
+
return new Response("", { status: 502 });
|
|
301
|
+
}
|
|
302
|
+
return new Response(
|
|
303
|
+
JSON.stringify({ status: 200, headers: {}, body: { ok: true } }),
|
|
304
|
+
{ status: 200 },
|
|
305
|
+
);
|
|
306
|
+
}) as unknown as typeof globalThis.fetch,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const conn = new PlatformOAuthConnection({ ...DEFAULT_OPTIONS, client });
|
|
310
|
+
const result = await conn.request({ method: "GET", path: "/test" });
|
|
311
|
+
|
|
312
|
+
expect(result.status).toBe(200);
|
|
313
|
+
expect(result.body).toEqual({ ok: true });
|
|
314
|
+
expect(callCount).toBe(3);
|
|
275
315
|
});
|
|
276
316
|
|
|
277
317
|
test("withToken throws clear error", async () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { VellumPlatformClient } from "../platform/client.js";
|
|
2
2
|
import { BackendError } from "../util/errors.js";
|
|
3
|
+
import { getLogger } from "../util/logger.js";
|
|
3
4
|
import { getHttpRetryDelay, isRetryableStatus, sleep } from "../util/retry.js";
|
|
4
5
|
import type {
|
|
5
6
|
OAuthConnection,
|
|
@@ -7,17 +8,22 @@ import type {
|
|
|
7
8
|
OAuthConnectionResponse,
|
|
8
9
|
} from "./connection.js";
|
|
9
10
|
|
|
11
|
+
const log = getLogger("platform-oauth-connection");
|
|
10
12
|
const MAX_RETRIES = 3;
|
|
11
13
|
|
|
12
14
|
export class CredentialRequiredError extends BackendError {
|
|
13
|
-
constructor(
|
|
15
|
+
constructor(
|
|
16
|
+
message = "OAuth credential for this provider has expired or been revoked. The service needs to be reconnected.",
|
|
17
|
+
) {
|
|
14
18
|
super(message);
|
|
15
19
|
this.name = "CredentialRequiredError";
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export class ProviderUnreachableError extends BackendError {
|
|
20
|
-
constructor(
|
|
24
|
+
constructor(
|
|
25
|
+
message = "The external service provider is temporarily unreachable. This may be a transient issue — retry after a brief pause.",
|
|
26
|
+
) {
|
|
21
27
|
super(message);
|
|
22
28
|
this.name = "ProviderUnreachableError";
|
|
23
29
|
}
|
|
@@ -107,19 +113,26 @@ export class PlatformOAuthConnection implements OAuthConnection {
|
|
|
107
113
|
throw new CredentialRequiredError();
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
if (response.status === 502) {
|
|
111
|
-
throw new ProviderUnreachableError();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
116
|
if (
|
|
115
117
|
!response.ok &&
|
|
116
118
|
isRetryableStatus(response.status) &&
|
|
117
119
|
attempt < MAX_RETRIES
|
|
118
120
|
) {
|
|
121
|
+
log.warn(
|
|
122
|
+
{ status: response.status, attempt, provider: "platform-proxy" },
|
|
123
|
+
`Retryable status ${response.status} from platform proxy (attempt ${attempt + 1}/${MAX_RETRIES + 1})`,
|
|
124
|
+
);
|
|
119
125
|
await sleep(getHttpRetryDelay(response, attempt));
|
|
120
126
|
continue;
|
|
121
127
|
}
|
|
122
128
|
|
|
129
|
+
if (response.status === 502) {
|
|
130
|
+
const detail = await response.text().catch(() => "");
|
|
131
|
+
throw new ProviderUnreachableError(
|
|
132
|
+
`The external service provider is temporarily unreachable (HTTP 502).${detail ? ` Detail: ${detail}` : ""} This may be a transient issue — retry after a brief pause.`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
123
136
|
if (!response.ok) {
|
|
124
137
|
throw new BackendError(
|
|
125
138
|
`Platform proxy returned unexpected status ${response.status}`,
|
|
@@ -77,7 +77,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
77
77
|
pingUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
|
|
78
78
|
baseUrl: "https://gmail.googleapis.com/gmail/v1/users/me",
|
|
79
79
|
displayLabel: "Google",
|
|
80
|
-
description: "Gmail, Calendar, and Contacts",
|
|
80
|
+
description: "Gmail, Calendar, Drive, and Contacts",
|
|
81
81
|
dashboardUrl: "https://console.cloud.google.com/apis/credentials",
|
|
82
82
|
clientIdPlaceholder: "123456789.apps.googleusercontent.com",
|
|
83
83
|
logoUrl: "https://cdn.simpleicons.org/google",
|
|
@@ -88,6 +88,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
88
88
|
"https://www.googleapis.com/auth/gmail.settings.basic",
|
|
89
89
|
"https://www.googleapis.com/auth/calendar.readonly",
|
|
90
90
|
"https://www.googleapis.com/auth/calendar.events",
|
|
91
|
+
"https://www.googleapis.com/auth/drive",
|
|
91
92
|
"https://www.googleapis.com/auth/userinfo.email",
|
|
92
93
|
"https://www.googleapis.com/auth/contacts.readonly",
|
|
93
94
|
],
|
|
@@ -722,6 +723,14 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
722
723
|
requiresClientSecret: false,
|
|
723
724
|
logoUrl: "https://cdn.simpleicons.org/slack",
|
|
724
725
|
defaultScopes: [],
|
|
726
|
+
injectionTemplates: [
|
|
727
|
+
{
|
|
728
|
+
hostPattern: "slack.com",
|
|
729
|
+
injectionType: "header",
|
|
730
|
+
headerName: "Authorization",
|
|
731
|
+
valuePrefix: "Bearer ",
|
|
732
|
+
},
|
|
733
|
+
],
|
|
725
734
|
},
|
|
726
735
|
|
|
727
736
|
telegram: {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getProtectedDir,
|
|
22
22
|
getWorkspaceDir,
|
|
23
23
|
getWorkspaceHooksDir,
|
|
24
|
+
getWorkspacePluginsDir,
|
|
24
25
|
} from "../util/platform.js";
|
|
25
26
|
import {
|
|
26
27
|
type ApprovalContext,
|
|
@@ -255,6 +256,7 @@ function buildFileContext(): FileContext {
|
|
|
255
256
|
protectedDir: getProtectedDir(),
|
|
256
257
|
deprecatedDir: getDeprecatedDir(),
|
|
257
258
|
hooksDir: getWorkspaceHooksDir(),
|
|
259
|
+
pluginsDir: getWorkspacePluginsDir(),
|
|
258
260
|
actorTokenSigningKeyPath: join(
|
|
259
261
|
getProtectedDir(),
|
|
260
262
|
"actor-token-signing-key",
|