@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
|
@@ -80,11 +80,6 @@ describe("titleGenerate pipeline", () => {
|
|
|
80
80
|
manifest: {
|
|
81
81
|
name: "default-title-generate",
|
|
82
82
|
version: "1.0.0",
|
|
83
|
-
provides: { titleGenerate: "v1" },
|
|
84
|
-
requires: {
|
|
85
|
-
pluginRuntime: "v1",
|
|
86
|
-
titleGenerateApi: "v1",
|
|
87
|
-
},
|
|
88
83
|
},
|
|
89
84
|
});
|
|
90
85
|
});
|
|
@@ -149,10 +144,6 @@ describe("titleGenerate pipeline", () => {
|
|
|
149
144
|
manifest: {
|
|
150
145
|
name: "custom-deterministic-title",
|
|
151
146
|
version: "0.0.1",
|
|
152
|
-
requires: {
|
|
153
|
-
pluginRuntime: "v1",
|
|
154
|
-
titleGenerateApi: "v1",
|
|
155
|
-
},
|
|
156
147
|
},
|
|
157
148
|
middleware: { titleGenerate: deterministicMw },
|
|
158
149
|
};
|
|
@@ -201,10 +192,6 @@ describe("titleGenerate pipeline", () => {
|
|
|
201
192
|
manifest: {
|
|
202
193
|
name: "observer",
|
|
203
194
|
version: "0.0.1",
|
|
204
|
-
requires: {
|
|
205
|
-
pluginRuntime: "v1",
|
|
206
|
-
titleGenerateApi: "v1",
|
|
207
|
-
},
|
|
208
195
|
},
|
|
209
196
|
middleware: { titleGenerate: passthroughMw },
|
|
210
197
|
});
|
|
@@ -338,7 +338,6 @@ describe("tokenEstimate pipeline — custom override", () => {
|
|
|
338
338
|
manifest: {
|
|
339
339
|
name: "custom-token-estimate",
|
|
340
340
|
version: "1.0.0",
|
|
341
|
-
requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
|
|
342
341
|
},
|
|
343
342
|
middleware: { tokenEstimate: override },
|
|
344
343
|
};
|
|
@@ -376,7 +375,6 @@ describe("tokenEstimate pipeline — custom override", () => {
|
|
|
376
375
|
manifest: {
|
|
377
376
|
name: "doubling-token-estimate",
|
|
378
377
|
version: "1.0.0",
|
|
379
|
-
requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
|
|
380
378
|
},
|
|
381
379
|
middleware: { tokenEstimate: doubler },
|
|
382
380
|
};
|
|
@@ -420,7 +418,6 @@ describe("tokenEstimate pipeline — default does not shadow late plugins", () =
|
|
|
420
418
|
manifest: {
|
|
421
419
|
name: "late-registered-observer",
|
|
422
420
|
version: "1.0.0",
|
|
423
|
-
requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
|
|
424
421
|
},
|
|
425
422
|
middleware: { tokenEstimate: observer },
|
|
426
423
|
};
|
|
@@ -150,7 +150,6 @@ describe("toolError pipeline", () => {
|
|
|
150
150
|
manifest: {
|
|
151
151
|
name: "custom-tool-error",
|
|
152
152
|
version: "0.0.1",
|
|
153
|
-
requires: { pluginRuntime: "v1", toolErrorApi: "v1" },
|
|
154
153
|
},
|
|
155
154
|
middleware: { toolError: customMiddleware },
|
|
156
155
|
};
|
|
@@ -176,7 +175,6 @@ describe("toolError pipeline", () => {
|
|
|
176
175
|
manifest: {
|
|
177
176
|
name: "no-nudge",
|
|
178
177
|
version: "0.0.1",
|
|
179
|
-
requires: { pluginRuntime: "v1", toolErrorApi: "v1" },
|
|
180
178
|
},
|
|
181
179
|
middleware: { toolError: suppressingMiddleware },
|
|
182
180
|
};
|
|
@@ -227,7 +225,6 @@ describe("toolError pipeline", () => {
|
|
|
227
225
|
manifest: {
|
|
228
226
|
name: "late-user-plugin",
|
|
229
227
|
version: "0.0.1",
|
|
230
|
-
requires: { pluginRuntime: "v1", toolErrorApi: "v1" },
|
|
231
228
|
},
|
|
232
229
|
middleware: { toolError: userMiddleware },
|
|
233
230
|
});
|
|
@@ -249,7 +249,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
|
|
|
249
249
|
manifest: {
|
|
250
250
|
name: "spy-tool-execute",
|
|
251
251
|
version: "0.0.1",
|
|
252
|
-
requires: { pluginRuntime: "v1" },
|
|
253
252
|
},
|
|
254
253
|
middleware: { toolExecute: spyMiddleware },
|
|
255
254
|
};
|
|
@@ -308,7 +307,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
|
|
|
308
307
|
manifest: {
|
|
309
308
|
name: "short-circuit-tool-execute",
|
|
310
309
|
version: "0.0.1",
|
|
311
|
-
requires: { pluginRuntime: "v1" },
|
|
312
310
|
},
|
|
313
311
|
middleware: { toolExecute: shortCircuit },
|
|
314
312
|
};
|
|
@@ -342,7 +340,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
|
|
|
342
340
|
manifest: {
|
|
343
341
|
name: "slow-tool-execute",
|
|
344
342
|
version: "0.0.1",
|
|
345
|
-
requires: { pluginRuntime: "v1" },
|
|
346
343
|
},
|
|
347
344
|
middleware: { toolExecute: slow },
|
|
348
345
|
});
|
|
@@ -388,7 +385,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
|
|
|
388
385
|
manifest: {
|
|
389
386
|
name: "outer-tool-execute",
|
|
390
387
|
version: "0.0.1",
|
|
391
|
-
requires: { pluginRuntime: "v1" },
|
|
392
388
|
},
|
|
393
389
|
middleware: { toolExecute: outer },
|
|
394
390
|
});
|
|
@@ -396,7 +392,6 @@ describe("ToolExecutor.execute → toolExecute pipeline", () => {
|
|
|
396
392
|
manifest: {
|
|
397
393
|
name: "inner-tool-execute",
|
|
398
394
|
version: "0.0.1",
|
|
399
|
-
requires: { pluginRuntime: "v1" },
|
|
400
395
|
},
|
|
401
396
|
middleware: { toolExecute: inner },
|
|
402
397
|
});
|
|
@@ -242,7 +242,7 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
242
242
|
);
|
|
243
243
|
|
|
244
244
|
expect(result.isError).toBe(true);
|
|
245
|
-
expect(result.content).toContain("Permission denied
|
|
245
|
+
expect(result.content).toContain("Permission denied");
|
|
246
246
|
expect(events.map((event) => event.type)).toEqual([
|
|
247
247
|
"start",
|
|
248
248
|
"permission_prompt",
|
|
@@ -462,6 +462,7 @@ describe("isSideEffectTool", () => {
|
|
|
462
462
|
"web_fetch",
|
|
463
463
|
"document_create",
|
|
464
464
|
"document_update",
|
|
465
|
+
"document_delete",
|
|
465
466
|
"schedule_create",
|
|
466
467
|
"schedule_update",
|
|
467
468
|
"schedule_delete",
|
|
@@ -670,6 +671,7 @@ describe("ToolExecutor forcePromptSideEffects enforcement", () => {
|
|
|
670
671
|
{ name: "web_fetch", input: { url: "https://example.com" } },
|
|
671
672
|
{ name: "document_create", input: { title: "doc", content: "body" } },
|
|
672
673
|
{ name: "document_update", input: { id: "doc-1", content: "updated" } },
|
|
674
|
+
{ name: "document_delete", input: { surface_id: "doc-1" } },
|
|
673
675
|
{
|
|
674
676
|
name: "credential_store",
|
|
675
677
|
input: { action: "store", name: "api-key", value: "secret" },
|
|
@@ -842,8 +844,12 @@ describe("ToolExecutor forcePromptSideEffects enforcement", () => {
|
|
|
842
844
|
// ---------------------------------------------------------------------------
|
|
843
845
|
|
|
844
846
|
// Import the real buildSanitizedEnv (not mocked) for baseline credential tests
|
|
845
|
-
const {
|
|
846
|
-
|
|
847
|
+
const {
|
|
848
|
+
buildSanitizedEnv,
|
|
849
|
+
KATA_SAFE_ENV_VARS,
|
|
850
|
+
SAFE_ENV_VARS,
|
|
851
|
+
ALWAYS_INJECTED_ENV_VARS,
|
|
852
|
+
} = await import("../tools/terminal/safe-env.js");
|
|
847
853
|
|
|
848
854
|
describe("buildSanitizedEnv — baseline: credential exclusion", () => {
|
|
849
855
|
// Credential-like env vars that must never appear in the sanitized env.
|
|
@@ -901,7 +907,11 @@ describe("buildSanitizedEnv — baseline: credential exclusion", () => {
|
|
|
901
907
|
});
|
|
902
908
|
|
|
903
909
|
test("sanitized env only contains keys from the allowlist", () => {
|
|
904
|
-
const allowed: string[] = [
|
|
910
|
+
const allowed: string[] = [
|
|
911
|
+
...SAFE_ENV_VARS,
|
|
912
|
+
...KATA_SAFE_ENV_VARS,
|
|
913
|
+
...ALWAYS_INJECTED_ENV_VARS,
|
|
914
|
+
];
|
|
905
915
|
const env = buildSanitizedEnv();
|
|
906
916
|
for (const key of Object.keys(env)) {
|
|
907
917
|
expect(allowed).toContain(key);
|
|
@@ -1211,7 +1221,9 @@ describe("ToolExecutionResult includes risk metadata from classifier assessment"
|
|
|
1211
1221
|
cachedAssessmentOverride = {
|
|
1212
1222
|
riskLevel: "low",
|
|
1213
1223
|
reason: "GET request to public URL",
|
|
1214
|
-
scopeOptions: [
|
|
1224
|
+
scopeOptions: [
|
|
1225
|
+
{ pattern: "https://example.com/.*", label: "example.com" },
|
|
1226
|
+
],
|
|
1215
1227
|
// allowlistOptions intentionally omitted — some classifiers don't emit them.
|
|
1216
1228
|
matchType: "registry",
|
|
1217
1229
|
};
|
|
@@ -236,10 +236,6 @@ describe("toolResultTruncate pipeline", () => {
|
|
|
236
236
|
manifest: {
|
|
237
237
|
name: "short-circuit",
|
|
238
238
|
version: "1.0.0",
|
|
239
|
-
requires: {
|
|
240
|
-
pluginRuntime: "v1",
|
|
241
|
-
toolResultTruncateApi: "v1",
|
|
242
|
-
},
|
|
243
239
|
},
|
|
244
240
|
middleware: { toolResultTruncate: shortCircuit },
|
|
245
241
|
});
|
|
@@ -274,10 +270,6 @@ describe("toolResultTruncate pipeline", () => {
|
|
|
274
270
|
manifest: {
|
|
275
271
|
name: "prefixer",
|
|
276
272
|
version: "1.0.0",
|
|
277
|
-
requires: {
|
|
278
|
-
pluginRuntime: "v1",
|
|
279
|
-
toolResultTruncateApi: "v1",
|
|
280
|
-
},
|
|
281
273
|
},
|
|
282
274
|
middleware: { toolResultTruncate: prefixer },
|
|
283
275
|
});
|
|
@@ -323,10 +315,6 @@ describe("toolResultTruncate pipeline", () => {
|
|
|
323
315
|
manifest: {
|
|
324
316
|
name: "late-user-plugin",
|
|
325
317
|
version: "0.0.1",
|
|
326
|
-
requires: {
|
|
327
|
-
pluginRuntime: "v1",
|
|
328
|
-
toolResultTruncateApi: "v1",
|
|
329
|
-
},
|
|
330
318
|
},
|
|
331
319
|
middleware: { toolResultTruncate: userMiddleware },
|
|
332
320
|
});
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for queryUnreportedTurnEvents.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that the JOIN to `conversations` correctly attaches the parent
|
|
5
|
+
* conversation's `conversationType` to each returned turn, so analytics
|
|
6
|
+
* downstream (DAU) can filter out background/scheduled prompts.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
10
|
+
|
|
11
|
+
import { makeMockLogger } from "./helpers/mock-logger.js";
|
|
12
|
+
|
|
13
|
+
mock.module("../util/logger.js", () => ({
|
|
14
|
+
getLogger: () => makeMockLogger(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
import { addMessage, createConversation } from "../memory/conversation-crud.js";
|
|
18
|
+
import { getDb } from "../memory/db-connection.js";
|
|
19
|
+
import { initializeDb } from "../memory/db-init.js";
|
|
20
|
+
import { messages } from "../memory/schema.js";
|
|
21
|
+
import { queryUnreportedTurnEvents } from "../memory/turn-events-store.js";
|
|
22
|
+
|
|
23
|
+
initializeDb();
|
|
24
|
+
|
|
25
|
+
function purge(): void {
|
|
26
|
+
const db = getDb();
|
|
27
|
+
// Wipe messages then conversations to keep tests independent. FK cascade
|
|
28
|
+
// also removes any dependent rows.
|
|
29
|
+
db.run("DELETE FROM messages");
|
|
30
|
+
db.run("DELETE FROM conversations");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
purge();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Insert a user message at a specific epoch-millis timestamp so we can
|
|
39
|
+
* assert ordering and the watermark cursor.
|
|
40
|
+
*/
|
|
41
|
+
async function insertUserMessageAt(
|
|
42
|
+
conversationId: string,
|
|
43
|
+
content: string,
|
|
44
|
+
createdAt: number,
|
|
45
|
+
): Promise<string> {
|
|
46
|
+
const message = await addMessage(conversationId, "user", content);
|
|
47
|
+
// addMessage stamps createdAt to monotonic now(); rewrite for
|
|
48
|
+
// deterministic ordering in the test.
|
|
49
|
+
const db = getDb();
|
|
50
|
+
db.run(
|
|
51
|
+
`UPDATE messages SET created_at = ${createdAt} WHERE id = '${message.id}'`,
|
|
52
|
+
);
|
|
53
|
+
return message.id;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe("queryUnreportedTurnEvents", () => {
|
|
57
|
+
test("attaches conversationId, conversationType, and turnIndex for a standard conversation", async () => {
|
|
58
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
59
|
+
await insertUserMessageAt(conv.id, "hello", 1000);
|
|
60
|
+
|
|
61
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
62
|
+
expect(events.length).toBe(1);
|
|
63
|
+
expect(events[0].conversationId).toBe(conv.id);
|
|
64
|
+
expect(events[0].conversationType).toBe("standard");
|
|
65
|
+
// The single user message in this conversation is turn 1.
|
|
66
|
+
expect(events[0].turnIndex).toBe(1);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("attaches conversationType for background and scheduled conversations", async () => {
|
|
70
|
+
const bg = createConversation({ conversationType: "background" });
|
|
71
|
+
const sched = createConversation({ conversationType: "scheduled" });
|
|
72
|
+
const std = createConversation({ conversationType: "standard" });
|
|
73
|
+
|
|
74
|
+
const bgMsg = await insertUserMessageAt(bg.id, "bg prompt", 1000);
|
|
75
|
+
const schedMsg = await insertUserMessageAt(sched.id, "sched prompt", 2000);
|
|
76
|
+
const stdMsg = await insertUserMessageAt(std.id, "user typed this", 3000);
|
|
77
|
+
|
|
78
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
79
|
+
const byId = Object.fromEntries(events.map((e) => [e.id, e]));
|
|
80
|
+
|
|
81
|
+
expect(byId[bgMsg].conversationType).toBe("background");
|
|
82
|
+
expect(byId[schedMsg].conversationType).toBe("scheduled");
|
|
83
|
+
expect(byId[stdMsg].conversationType).toBe("standard");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("excludes tool_result and web_search_tool_result content patterns", async () => {
|
|
87
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
88
|
+
|
|
89
|
+
// Real user turn
|
|
90
|
+
const realId = await insertUserMessageAt(conv.id, "real user text", 1000);
|
|
91
|
+
|
|
92
|
+
// Synthetic "user" rows that wrap tool results: these should be filtered
|
|
93
|
+
const db = getDb();
|
|
94
|
+
db.insert(messages)
|
|
95
|
+
.values({
|
|
96
|
+
id: "tool-result-id",
|
|
97
|
+
conversationId: conv.id,
|
|
98
|
+
role: "user",
|
|
99
|
+
content: JSON.stringify([
|
|
100
|
+
{ type: "tool_result", tool_use_id: "x", content: "" },
|
|
101
|
+
]),
|
|
102
|
+
createdAt: 2000,
|
|
103
|
+
})
|
|
104
|
+
.run();
|
|
105
|
+
db.insert(messages)
|
|
106
|
+
.values({
|
|
107
|
+
id: "web-search-tool-result-id",
|
|
108
|
+
conversationId: conv.id,
|
|
109
|
+
role: "user",
|
|
110
|
+
content: JSON.stringify([
|
|
111
|
+
{ type: "web_search_tool_result", tool_use_id: "y", content: "" },
|
|
112
|
+
]),
|
|
113
|
+
createdAt: 3000,
|
|
114
|
+
})
|
|
115
|
+
.run();
|
|
116
|
+
|
|
117
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
118
|
+
expect(events.length).toBe(1);
|
|
119
|
+
expect(events[0].id).toBe(realId);
|
|
120
|
+
expect(events[0].conversationType).toBe("standard");
|
|
121
|
+
// Tool-result rows must NOT increment the turn index: this is the
|
|
122
|
+
// only real user turn in the conversation, so its index is 1 even
|
|
123
|
+
// though two synthetic role="user" rows exist with later timestamps.
|
|
124
|
+
expect(events[0].turnIndex).toBe(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("turnIndex counts real user turns in (createdAt, id) order within a conversation", async () => {
|
|
128
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
129
|
+
const m1 = await insertUserMessageAt(conv.id, "first", 1000);
|
|
130
|
+
const m2 = await insertUserMessageAt(conv.id, "second", 2000);
|
|
131
|
+
const m3 = await insertUserMessageAt(conv.id, "third", 3000);
|
|
132
|
+
|
|
133
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
134
|
+
const byId = Object.fromEntries(events.map((e) => [e.id, e]));
|
|
135
|
+
expect(byId[m1].turnIndex).toBe(1);
|
|
136
|
+
expect(byId[m2].turnIndex).toBe(2);
|
|
137
|
+
expect(byId[m3].turnIndex).toBe(3);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("turnIndex resets across conversations", async () => {
|
|
141
|
+
const a = createConversation({ conversationType: "standard" });
|
|
142
|
+
const b = createConversation({ conversationType: "standard" });
|
|
143
|
+
const a1 = await insertUserMessageAt(a.id, "a first", 1000);
|
|
144
|
+
const b1 = await insertUserMessageAt(b.id, "b first", 1500);
|
|
145
|
+
const a2 = await insertUserMessageAt(a.id, "a second", 2000);
|
|
146
|
+
|
|
147
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
148
|
+
const byId = Object.fromEntries(events.map((e) => [e.id, e]));
|
|
149
|
+
// Conversation A: 1, 2. Conversation B: 1 (independent of A).
|
|
150
|
+
expect(byId[a1].turnIndex).toBe(1);
|
|
151
|
+
expect(byId[a2].turnIndex).toBe(2);
|
|
152
|
+
expect(byId[b1].turnIndex).toBe(1);
|
|
153
|
+
// And the conversation_id labels them correctly.
|
|
154
|
+
expect(byId[a1].conversationId).toBe(a.id);
|
|
155
|
+
expect(byId[b1].conversationId).toBe(b.id);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("turnIndex skips tool_result rows even when they're interleaved", async () => {
|
|
159
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
160
|
+
const real1 = await insertUserMessageAt(conv.id, "first real", 1000);
|
|
161
|
+
|
|
162
|
+
// Inject a tool_result row between the two real turns. The
|
|
163
|
+
// correlated subquery must use the same content filter as the
|
|
164
|
+
// outer query, otherwise turn_index would jump by 2 instead of 1.
|
|
165
|
+
const db = getDb();
|
|
166
|
+
db.insert(messages)
|
|
167
|
+
.values({
|
|
168
|
+
id: "interleaved-tool-result",
|
|
169
|
+
conversationId: conv.id,
|
|
170
|
+
role: "user",
|
|
171
|
+
content: JSON.stringify([
|
|
172
|
+
{ type: "tool_result", tool_use_id: "x", content: "" },
|
|
173
|
+
]),
|
|
174
|
+
createdAt: 1500,
|
|
175
|
+
})
|
|
176
|
+
.run();
|
|
177
|
+
|
|
178
|
+
const real2 = await insertUserMessageAt(conv.id, "second real", 2000);
|
|
179
|
+
|
|
180
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
181
|
+
const byId = Object.fromEntries(events.map((e) => [e.id, e]));
|
|
182
|
+
expect(events.length).toBe(2);
|
|
183
|
+
expect(byId[real1].turnIndex).toBe(1);
|
|
184
|
+
expect(byId[real2].turnIndex).toBe(2);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("respects the cursor and returns events in (createdAt, id) order", async () => {
|
|
188
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
189
|
+
const m1 = await insertUserMessageAt(conv.id, "first", 1000);
|
|
190
|
+
const m2 = await insertUserMessageAt(conv.id, "second", 2000);
|
|
191
|
+
const m3 = await insertUserMessageAt(conv.id, "third", 3000);
|
|
192
|
+
|
|
193
|
+
// Cursor at (1500, undefined) should skip m1 and return m2, m3 in order.
|
|
194
|
+
const after = queryUnreportedTurnEvents(1500, undefined, 100);
|
|
195
|
+
expect(after.map((e) => e.id)).toEqual([m2, m3]);
|
|
196
|
+
|
|
197
|
+
// Sanity: pulling from the start returns all three with correct types.
|
|
198
|
+
const all = queryUnreportedTurnEvents(0, undefined, 100);
|
|
199
|
+
expect(all.map((e) => e.id)).toEqual([m1, m2, m3]);
|
|
200
|
+
for (const e of all) {
|
|
201
|
+
expect(e.conversationType).toBe("standard");
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("extracts interfaceId, channelId, and clientMetadata from messages.metadata", async () => {
|
|
206
|
+
// Three user messages with different metadata shapes to cover the
|
|
207
|
+
// realistic spectrum of attribution carried on messages.metadata:
|
|
208
|
+
// - Full interactive: macOS surface, vellum channel, with a client
|
|
209
|
+
// block stamped by the (forthcoming) HTTP header middleware.
|
|
210
|
+
// - Channel inbound: Slack surface, no client headers (channel
|
|
211
|
+
// inbound paths don't carry browser context).
|
|
212
|
+
// - Legacy: a message persisted before metadata threading existed.
|
|
213
|
+
const conv = createConversation({ conversationType: "standard" });
|
|
214
|
+
|
|
215
|
+
const macOsMsg = await addMessage(conv.id, "user", "hi from desktop", {
|
|
216
|
+
userMessageInterface: "macos",
|
|
217
|
+
userMessageChannel: "vellum",
|
|
218
|
+
client: {
|
|
219
|
+
os: "darwin",
|
|
220
|
+
interface_version: "0.8.2",
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
const slackMsg = await addMessage(conv.id, "user", "hi from slack", {
|
|
224
|
+
userMessageInterface: "slack",
|
|
225
|
+
userMessageChannel: "slack",
|
|
226
|
+
});
|
|
227
|
+
const legacyMsg = await addMessage(conv.id, "user", "hi from the past");
|
|
228
|
+
|
|
229
|
+
const events = queryUnreportedTurnEvents(0, undefined, 100);
|
|
230
|
+
const byId = Object.fromEntries(events.map((e) => [e.id, e]));
|
|
231
|
+
|
|
232
|
+
expect(byId[macOsMsg.id]).toBeDefined();
|
|
233
|
+
expect(byId[macOsMsg.id].interfaceId).toBe("macos");
|
|
234
|
+
expect(byId[macOsMsg.id].channelId).toBe("vellum");
|
|
235
|
+
// clientMetadata is returned as raw JSON text -- the reporter parses it.
|
|
236
|
+
// We verify it round-trips back to the input object.
|
|
237
|
+
expect(byId[macOsMsg.id].clientMetadata).not.toBeNull();
|
|
238
|
+
expect(
|
|
239
|
+
JSON.parse(byId[macOsMsg.id].clientMetadata as string),
|
|
240
|
+
).toMatchObject({
|
|
241
|
+
os: "darwin",
|
|
242
|
+
interface_version: "0.8.2",
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect(byId[slackMsg.id].interfaceId).toBe("slack");
|
|
246
|
+
expect(byId[slackMsg.id].channelId).toBe("slack");
|
|
247
|
+
expect(byId[slackMsg.id].clientMetadata).toBeNull();
|
|
248
|
+
|
|
249
|
+
// Legacy rows (no metadata threading) return null for all three
|
|
250
|
+
// attribution fields -- downstream analytics treats these as
|
|
251
|
+
// "unknown" without breaking the batch.
|
|
252
|
+
expect(byId[legacyMsg.id].interfaceId).toBeNull();
|
|
253
|
+
expect(byId[legacyMsg.id].channelId).toBeNull();
|
|
254
|
+
expect(byId[legacyMsg.id].clientMetadata).toBeNull();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
@@ -1392,6 +1392,10 @@ describe("twilio webhook routes", () => {
|
|
|
1392
1392
|
|
|
1393
1393
|
expect(result.success).toBe(true);
|
|
1394
1394
|
expect(result.hasCredentials).toBe(true);
|
|
1395
|
+
expect(mockRawConfigStore.twilio).toEqual({
|
|
1396
|
+
accountSid: "AC_new_credentials",
|
|
1397
|
+
setupStarted: true,
|
|
1398
|
+
});
|
|
1395
1399
|
});
|
|
1396
1400
|
|
|
1397
1401
|
test("clearing credentials succeeds", async () => {
|
|
@@ -81,7 +81,6 @@ registerPlugin({
|
|
|
81
81
|
manifest: {
|
|
82
82
|
name: "my-plugin",
|
|
83
83
|
version: "0.0.1",
|
|
84
|
-
requires: { pluginRuntime: "v1" },
|
|
85
84
|
},
|
|
86
85
|
});
|
|
87
86
|
`,
|
|
@@ -111,7 +110,6 @@ registerPlugin({
|
|
|
111
110
|
manifest: {
|
|
112
111
|
name: "good-plugin",
|
|
113
112
|
version: "0.0.1",
|
|
114
|
-
requires: { pluginRuntime: "v1" },
|
|
115
113
|
},
|
|
116
114
|
});
|
|
117
115
|
`,
|
|
@@ -151,7 +149,6 @@ registerPlugin({
|
|
|
151
149
|
manifest: {
|
|
152
150
|
name: "hanging-plugin",
|
|
153
151
|
version: "0.0.1",
|
|
154
|
-
requires: { pluginRuntime: "v1" },
|
|
155
152
|
},
|
|
156
153
|
});
|
|
157
154
|
`,
|
|
@@ -163,7 +160,6 @@ registerPlugin({
|
|
|
163
160
|
manifest: {
|
|
164
161
|
name: "healthy-plugin",
|
|
165
162
|
version: "0.0.1",
|
|
166
|
-
requires: { pluginRuntime: "v1" },
|
|
167
163
|
},
|
|
168
164
|
});
|
|
169
165
|
`,
|
|
@@ -198,7 +194,6 @@ registerPlugin({
|
|
|
198
194
|
manifest: {
|
|
199
195
|
name: "slow-late-plugin",
|
|
200
196
|
version: "0.0.1",
|
|
201
|
-
requires: { pluginRuntime: "v1" },
|
|
202
197
|
},
|
|
203
198
|
});
|
|
204
199
|
`,
|
|
@@ -305,7 +300,6 @@ registerPlugin({
|
|
|
305
300
|
manifest: {
|
|
306
301
|
name: "healthy-legacy",
|
|
307
302
|
version: "0.0.1",
|
|
308
|
-
requires: { pluginRuntime: "v1" },
|
|
309
303
|
},
|
|
310
304
|
});
|
|
311
305
|
`,
|
|
@@ -330,7 +324,6 @@ registerPlugin({
|
|
|
330
324
|
manifest: {
|
|
331
325
|
name: "old-style",
|
|
332
326
|
version: "0.0.1",
|
|
333
|
-
requires: { pluginRuntime: "v1" },
|
|
334
327
|
},
|
|
335
328
|
});
|
|
336
329
|
`,
|