@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
package/src/home/feed-types.ts
CHANGED
|
@@ -38,6 +38,14 @@ export type FeedItemStatus = "new" | "seen" | "acted_on" | "dismissed";
|
|
|
38
38
|
/** Visual urgency treatment — controls badge color independently of sort priority. */
|
|
39
39
|
export type FeedItemUrgency = "low" | "medium" | "high" | "critical";
|
|
40
40
|
|
|
41
|
+
/** Broad category for grouping and filtering feed items. */
|
|
42
|
+
export type FeedItemCategory =
|
|
43
|
+
| "security"
|
|
44
|
+
| "scheduling"
|
|
45
|
+
| "background"
|
|
46
|
+
| "email"
|
|
47
|
+
| "system";
|
|
48
|
+
|
|
41
49
|
/**
|
|
42
50
|
* A single action button attached to a feed item.
|
|
43
51
|
*
|
|
@@ -81,7 +89,13 @@ export interface FeedItem {
|
|
|
81
89
|
type: FeedItemType;
|
|
82
90
|
/** Integer in [0, 100]; higher values sort earlier. */
|
|
83
91
|
priority: number;
|
|
84
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Optional short header. Omit when the source did not supply one — the
|
|
94
|
+
* notification pipeline never manufactures a title from rendered copy
|
|
95
|
+
* (LLM-echoed bodies stutter against `summary`). Clients fall back to
|
|
96
|
+
* `summary` when rendering a row.
|
|
97
|
+
*/
|
|
98
|
+
title?: string;
|
|
85
99
|
summary: string;
|
|
86
100
|
/** Event time (ISO-8601). */
|
|
87
101
|
timestamp: string;
|
|
@@ -96,6 +110,14 @@ export interface FeedItem {
|
|
|
96
110
|
conversationId?: string;
|
|
97
111
|
/** Server-driven detail panel descriptor; when present, the client opens this panel kind. */
|
|
98
112
|
detailPanel?: FeedItemDetailPanel;
|
|
113
|
+
/** Broad category for grouping and filtering feed items. */
|
|
114
|
+
category?: FeedItemCategory;
|
|
115
|
+
/** True when this item represents an assistant-initiated share or a high-importance system event. Used by clients to split inbox vs activity surfaces. */
|
|
116
|
+
noteworthy?: boolean;
|
|
117
|
+
/** True when the assistant herself emitted this item (e.g. via the `notifications send` skill). Drives clients to swap the row's leading icon for the persona avatar; system-generated items keep the category icon. */
|
|
118
|
+
fromAssistant?: boolean;
|
|
119
|
+
/** Arbitrary structured data the detail panel or other consumers can use. */
|
|
120
|
+
metadata?: Record<string, unknown>;
|
|
99
121
|
/** Internal: ISO-8601 writer-record time, used for ordering + TTL. */
|
|
100
122
|
createdAt: string;
|
|
101
123
|
}
|
|
@@ -164,6 +186,14 @@ const feedItemDetailPanelSchema = z.object({
|
|
|
164
186
|
kind: feedItemDetailPanelKindSchema,
|
|
165
187
|
});
|
|
166
188
|
|
|
189
|
+
const feedItemCategorySchema = z.enum([
|
|
190
|
+
"security",
|
|
191
|
+
"scheduling",
|
|
192
|
+
"background",
|
|
193
|
+
"email",
|
|
194
|
+
"system",
|
|
195
|
+
]);
|
|
196
|
+
|
|
167
197
|
/**
|
|
168
198
|
* Schema for a single `FeedItem`.
|
|
169
199
|
*
|
|
@@ -178,7 +208,7 @@ export const feedItemSchema = z.object({
|
|
|
178
208
|
id: z.string(),
|
|
179
209
|
type: feedItemTypeSchema,
|
|
180
210
|
priority: z.number().int().min(0).max(100),
|
|
181
|
-
title: z.string(),
|
|
211
|
+
title: z.string().optional(),
|
|
182
212
|
summary: z.string(),
|
|
183
213
|
timestamp: z.string(),
|
|
184
214
|
status: feedItemStatusSchema.default("new"),
|
|
@@ -187,6 +217,10 @@ export const feedItemSchema = z.object({
|
|
|
187
217
|
urgency: feedItemUrgencySchema.optional(),
|
|
188
218
|
conversationId: z.string().optional(),
|
|
189
219
|
detailPanel: feedItemDetailPanelSchema.optional(),
|
|
220
|
+
category: feedItemCategorySchema.optional(),
|
|
221
|
+
noteworthy: z.boolean().optional(),
|
|
222
|
+
fromAssistant: z.boolean().optional(),
|
|
223
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
190
224
|
createdAt: z.string(),
|
|
191
225
|
});
|
|
192
226
|
|
|
@@ -44,6 +44,7 @@ export async function emitPostConnectNudge(service: string): Promise<void> {
|
|
|
44
44
|
"I can triage your inbox, summarize new emails, or draft replies to important threads.",
|
|
45
45
|
timestamp: now.toISOString(),
|
|
46
46
|
status: "new",
|
|
47
|
+
category: "email",
|
|
47
48
|
expiresAt,
|
|
48
49
|
createdAt: now.toISOString(),
|
|
49
50
|
actions: [
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import { red } from "./cli/lib/cli-colors.js";
|
|
4
|
+
import {
|
|
5
|
+
detectUnknownCommand,
|
|
6
|
+
formatUnknownCommandMessage,
|
|
7
|
+
} from "./cli/lib/unknown-command.js";
|
|
3
8
|
import { buildCliProgram } from "./cli/program.js";
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
const program = await buildCliProgram();
|
|
11
|
+
|
|
12
|
+
// Commander processes `--help` before any action or hook fires, so
|
|
13
|
+
// `assistant <unknown> --help` would dump the root help instead of flagging
|
|
14
|
+
// the typo. Pre-scan argv so the unknown-command error wins over the help
|
|
15
|
+
// short-circuit. See cli/lib/unknown-command.ts.
|
|
16
|
+
const unknown = detectUnknownCommand(program, process.argv.slice(2));
|
|
17
|
+
if (unknown) {
|
|
18
|
+
process.stderr.write(`${red(formatUnknownCommandMessage(unknown))}\n`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
program.parse();
|
package/src/ipc/cli-client.ts
CHANGED
|
@@ -135,19 +135,26 @@ export async function cliIpcCall<T = unknown>(
|
|
|
135
135
|
|
|
136
136
|
const reqId = crypto.randomUUID();
|
|
137
137
|
|
|
138
|
-
opts?.signal?.addEventListener(
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
opts?.signal?.addEventListener(
|
|
139
|
+
"abort",
|
|
140
|
+
() => {
|
|
141
|
+
finish({ ok: false, error: "Request aborted" });
|
|
142
|
+
},
|
|
143
|
+
{ once: true },
|
|
144
|
+
);
|
|
141
145
|
|
|
142
146
|
const reader = new IpcFrameReader(
|
|
143
147
|
(envelope) => {
|
|
144
148
|
if (envelope.id !== reqId) return;
|
|
145
149
|
const msg = envelope as IpcResponse;
|
|
146
150
|
if (msg.error) {
|
|
147
|
-
finish({
|
|
151
|
+
finish({
|
|
152
|
+
ok: false,
|
|
153
|
+
error: msg.error,
|
|
148
154
|
...(msg.statusCode != null && { statusCode: msg.statusCode }),
|
|
149
155
|
...(msg.errorCode != null && { errorCode: msg.errorCode }),
|
|
150
|
-
...(msg.errorDetails != null && { errorDetails: msg.errorDetails })
|
|
156
|
+
...(msg.errorDetails != null && { errorDetails: msg.errorDetails }),
|
|
157
|
+
});
|
|
151
158
|
} else {
|
|
152
159
|
finish({ ok: true, result: msg.result as T });
|
|
153
160
|
}
|
|
@@ -199,7 +206,13 @@ export async function cliIpcCallBinary(
|
|
|
199
206
|
opts?: { timeoutMs?: number; signal?: AbortSignal },
|
|
200
207
|
): Promise<
|
|
201
208
|
| { ok: true; headers: Record<string, string>; bytes: Uint8Array }
|
|
202
|
-
| {
|
|
209
|
+
| {
|
|
210
|
+
ok: false;
|
|
211
|
+
error: string;
|
|
212
|
+
statusCode?: number;
|
|
213
|
+
errorCode?: string;
|
|
214
|
+
errorDetails?: unknown;
|
|
215
|
+
}
|
|
203
216
|
> {
|
|
204
217
|
if (opts?.signal?.aborted) {
|
|
205
218
|
throw opts.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
@@ -215,7 +228,13 @@ export async function cliIpcCallBinary(
|
|
|
215
228
|
const finish = (
|
|
216
229
|
result:
|
|
217
230
|
| { ok: true; headers: Record<string, string>; bytes: Uint8Array }
|
|
218
|
-
| {
|
|
231
|
+
| {
|
|
232
|
+
ok: false;
|
|
233
|
+
error: string;
|
|
234
|
+
statusCode?: number;
|
|
235
|
+
errorCode?: string;
|
|
236
|
+
errorDetails?: unknown;
|
|
237
|
+
},
|
|
219
238
|
) => {
|
|
220
239
|
if (settled) return;
|
|
221
240
|
settled = true;
|
|
@@ -226,8 +245,14 @@ export async function cliIpcCallBinary(
|
|
|
226
245
|
};
|
|
227
246
|
|
|
228
247
|
const connectTimer = setTimeout(() => {
|
|
229
|
-
log.debug(
|
|
230
|
-
|
|
248
|
+
log.debug(
|
|
249
|
+
{ method, socketPath, timeoutMs: CONNECT_TIMEOUT_MS },
|
|
250
|
+
"CLI IPC binary connect timed out",
|
|
251
|
+
);
|
|
252
|
+
finish({
|
|
253
|
+
ok: false,
|
|
254
|
+
error: `Could not connect to the assistant at ${socketPath}.\nRun \`assistant status\` to check, or \`assistant gateway start\` to start it.`,
|
|
255
|
+
});
|
|
231
256
|
}, CONNECT_TIMEOUT_MS);
|
|
232
257
|
|
|
233
258
|
const socket = new Socket();
|
|
@@ -235,7 +260,10 @@ export async function cliIpcCallBinary(
|
|
|
235
260
|
|
|
236
261
|
socket.on("error", (err) => {
|
|
237
262
|
const code = (err as NodeJS.ErrnoException).code;
|
|
238
|
-
log.debug(
|
|
263
|
+
log.debug(
|
|
264
|
+
{ err, code, method, socketPath },
|
|
265
|
+
"CLI IPC binary socket error",
|
|
266
|
+
);
|
|
239
267
|
finish({
|
|
240
268
|
ok: false,
|
|
241
269
|
error:
|
|
@@ -258,23 +286,37 @@ export async function cliIpcCallBinary(
|
|
|
258
286
|
|
|
259
287
|
const reqId = crypto.randomUUID();
|
|
260
288
|
|
|
261
|
-
opts?.signal?.addEventListener(
|
|
262
|
-
|
|
263
|
-
|
|
289
|
+
opts?.signal?.addEventListener(
|
|
290
|
+
"abort",
|
|
291
|
+
() => {
|
|
292
|
+
finish({ ok: false, error: "Request aborted" });
|
|
293
|
+
},
|
|
294
|
+
{ once: true },
|
|
295
|
+
);
|
|
264
296
|
|
|
265
297
|
const reader = new IpcFrameReader(
|
|
266
298
|
(envelope, binary) => {
|
|
267
299
|
if (envelope.id !== reqId) return;
|
|
268
300
|
const msg = envelope as IpcResponse;
|
|
269
301
|
if (msg.error) {
|
|
270
|
-
finish({
|
|
302
|
+
finish({
|
|
303
|
+
ok: false,
|
|
304
|
+
error: msg.error,
|
|
271
305
|
...(msg.statusCode != null && { statusCode: msg.statusCode }),
|
|
272
306
|
...(msg.errorCode != null && { errorCode: msg.errorCode }),
|
|
273
|
-
...(msg.errorDetails != null && { errorDetails: msg.errorDetails })
|
|
307
|
+
...(msg.errorDetails != null && { errorDetails: msg.errorDetails }),
|
|
308
|
+
});
|
|
274
309
|
} else if (binary === undefined) {
|
|
275
|
-
finish({
|
|
310
|
+
finish({
|
|
311
|
+
ok: false,
|
|
312
|
+
error: "Expected binary frame but received JSON-only response",
|
|
313
|
+
});
|
|
276
314
|
} else {
|
|
277
|
-
finish({
|
|
315
|
+
finish({
|
|
316
|
+
ok: true,
|
|
317
|
+
headers: (envelope.headers ?? {}) as Record<string, string>,
|
|
318
|
+
bytes: binary,
|
|
319
|
+
});
|
|
278
320
|
}
|
|
279
321
|
},
|
|
280
322
|
(err) => finish({ ok: false, error: err.message }),
|
|
@@ -285,7 +327,10 @@ export async function cliIpcCallBinary(
|
|
|
285
327
|
writeMessage(socket, { id: reqId, method, params });
|
|
286
328
|
|
|
287
329
|
callTimer = setTimeout(() => {
|
|
288
|
-
log.debug(
|
|
330
|
+
log.debug(
|
|
331
|
+
{ method, socketPath, timeoutMs: callTimeoutMs },
|
|
332
|
+
"CLI IPC binary call timed out",
|
|
333
|
+
);
|
|
289
334
|
finish({ ok: false, error: "Request timed out" });
|
|
290
335
|
}, callTimeoutMs);
|
|
291
336
|
|
|
@@ -323,24 +368,42 @@ export async function cliIpcCallStream(
|
|
|
323
368
|
params?: Record<string, unknown>,
|
|
324
369
|
opts?: { firstByteTimeoutMs?: number; signal?: AbortSignal },
|
|
325
370
|
): Promise<
|
|
326
|
-
| {
|
|
327
|
-
|
|
371
|
+
| {
|
|
372
|
+
ok: true;
|
|
373
|
+
headers: Record<string, string>;
|
|
374
|
+
body: ReadableStream<Uint8Array>;
|
|
375
|
+
abort: () => void;
|
|
376
|
+
}
|
|
377
|
+
| {
|
|
378
|
+
ok: false;
|
|
379
|
+
error: string;
|
|
380
|
+
statusCode?: number;
|
|
381
|
+
errorCode?: string;
|
|
382
|
+
errorDetails?: unknown;
|
|
383
|
+
}
|
|
328
384
|
> {
|
|
329
385
|
if (opts?.signal?.aborted) {
|
|
330
386
|
throw opts.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
331
387
|
}
|
|
332
388
|
|
|
333
389
|
const socketPath = getAssistantSocketPath();
|
|
334
|
-
const firstByteTimeoutMs =
|
|
390
|
+
const firstByteTimeoutMs =
|
|
391
|
+
opts?.firstByteTimeoutMs ?? DEFAULT_FIRST_BYTE_TIMEOUT_MS;
|
|
335
392
|
|
|
336
393
|
return new Promise((resolve) => {
|
|
337
394
|
let settled = false;
|
|
338
395
|
let firstByteTimer: ReturnType<typeof setTimeout> | undefined;
|
|
339
|
-
let streamController:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
396
|
+
let streamController:
|
|
397
|
+
| ReadableStreamDefaultController<Uint8Array>
|
|
398
|
+
| undefined;
|
|
399
|
+
|
|
400
|
+
const finishError = (result: {
|
|
401
|
+
ok: false;
|
|
402
|
+
error: string;
|
|
403
|
+
statusCode?: number;
|
|
404
|
+
errorCode?: string;
|
|
405
|
+
errorDetails?: unknown;
|
|
406
|
+
}) => {
|
|
344
407
|
if (settled) return;
|
|
345
408
|
settled = true;
|
|
346
409
|
clearTimeout(connectTimer);
|
|
@@ -366,8 +429,14 @@ export async function cliIpcCallStream(
|
|
|
366
429
|
};
|
|
367
430
|
|
|
368
431
|
const connectTimer = setTimeout(() => {
|
|
369
|
-
log.debug(
|
|
370
|
-
|
|
432
|
+
log.debug(
|
|
433
|
+
{ method, socketPath, timeoutMs: CONNECT_TIMEOUT_MS },
|
|
434
|
+
"CLI IPC stream connect timed out",
|
|
435
|
+
);
|
|
436
|
+
finishError({
|
|
437
|
+
ok: false,
|
|
438
|
+
error: `Could not connect to the assistant at ${socketPath}.\nRun \`assistant status\` to check, or \`assistant gateway start\` to start it.`,
|
|
439
|
+
});
|
|
371
440
|
}, CONNECT_TIMEOUT_MS);
|
|
372
441
|
|
|
373
442
|
const socket = new Socket();
|
|
@@ -375,7 +444,10 @@ export async function cliIpcCallStream(
|
|
|
375
444
|
|
|
376
445
|
socket.on("error", (err) => {
|
|
377
446
|
const code = (err as NodeJS.ErrnoException).code;
|
|
378
|
-
log.debug(
|
|
447
|
+
log.debug(
|
|
448
|
+
{ err, code, method, socketPath },
|
|
449
|
+
"CLI IPC stream socket error",
|
|
450
|
+
);
|
|
379
451
|
if (!settled) {
|
|
380
452
|
finishError({
|
|
381
453
|
ok: false,
|
|
@@ -399,24 +471,35 @@ export async function cliIpcCallStream(
|
|
|
399
471
|
: "Connection closed before response",
|
|
400
472
|
});
|
|
401
473
|
} else if (streamController) {
|
|
402
|
-
streamController.error(
|
|
474
|
+
streamController.error(
|
|
475
|
+
new Error("Connection closed before stream ended"),
|
|
476
|
+
);
|
|
403
477
|
streamController = undefined;
|
|
404
478
|
}
|
|
405
479
|
});
|
|
406
480
|
|
|
407
481
|
const reqId = crypto.randomUUID();
|
|
408
482
|
|
|
409
|
-
opts?.signal?.addEventListener(
|
|
483
|
+
opts?.signal?.addEventListener(
|
|
484
|
+
"abort",
|
|
485
|
+
() => {
|
|
486
|
+
abort();
|
|
487
|
+
},
|
|
488
|
+
{ once: true },
|
|
489
|
+
);
|
|
410
490
|
|
|
411
491
|
const reader = new IpcFrameReader(
|
|
412
492
|
(envelope) => {
|
|
413
493
|
// Non-streaming envelope with error (e.g. method not found, auth failure)
|
|
414
494
|
if (envelope.id !== reqId) return;
|
|
415
495
|
const msg = envelope as IpcResponse;
|
|
416
|
-
finishError({
|
|
496
|
+
finishError({
|
|
497
|
+
ok: false,
|
|
498
|
+
error: msg.error ?? "Unexpected non-streaming response",
|
|
417
499
|
...(msg.statusCode != null && { statusCode: msg.statusCode }),
|
|
418
500
|
...(msg.errorCode != null && { errorCode: msg.errorCode }),
|
|
419
|
-
...(msg.errorDetails != null && { errorDetails: msg.errorDetails })
|
|
501
|
+
...(msg.errorDetails != null && { errorDetails: msg.errorDetails }),
|
|
502
|
+
});
|
|
420
503
|
},
|
|
421
504
|
(err) => finishError({ ok: false, error: err.message }),
|
|
422
505
|
{
|
|
@@ -437,7 +520,12 @@ export async function cliIpcCallStream(
|
|
|
437
520
|
});
|
|
438
521
|
settled = true;
|
|
439
522
|
clearTimeout(connectTimer);
|
|
440
|
-
resolve({
|
|
523
|
+
resolve({
|
|
524
|
+
ok: true,
|
|
525
|
+
headers: (envelope.headers ?? {}) as Record<string, string>,
|
|
526
|
+
body,
|
|
527
|
+
abort,
|
|
528
|
+
});
|
|
441
529
|
},
|
|
442
530
|
onStreamChunk: (chunk) => {
|
|
443
531
|
streamController?.enqueue(chunk);
|
|
@@ -455,8 +543,14 @@ export async function cliIpcCallStream(
|
|
|
455
543
|
writeMessage(socket, { id: reqId, method, params });
|
|
456
544
|
|
|
457
545
|
firstByteTimer = setTimeout(() => {
|
|
458
|
-
log.debug(
|
|
459
|
-
|
|
546
|
+
log.debug(
|
|
547
|
+
{ method, socketPath, timeoutMs: firstByteTimeoutMs },
|
|
548
|
+
"CLI IPC stream first-byte timeout",
|
|
549
|
+
);
|
|
550
|
+
finishError({
|
|
551
|
+
ok: false,
|
|
552
|
+
error: "Stream timed out waiting for first byte",
|
|
553
|
+
});
|
|
460
554
|
}, firstByteTimeoutMs);
|
|
461
555
|
|
|
462
556
|
socket.on("data", (chunk) => {
|
|
@@ -491,13 +585,21 @@ export function exitFromIpcResult(
|
|
|
491
585
|
_cmd?: unknown,
|
|
492
586
|
): never {
|
|
493
587
|
process.stderr.write((r.error ?? "Unknown error") + "\n");
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
588
|
+
process.exit(exitCodeFromIpcResult(r));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Map an IPC error result to its CLI process exit code without exiting.
|
|
593
|
+
*
|
|
594
|
+
* Use this when callers want to emit a structured response (e.g. a JSON
|
|
595
|
+
* error envelope in `--json` mode) before terminating with the same status
|
|
596
|
+
* code that {@link exitFromIpcResult} would produce.
|
|
597
|
+
*
|
|
598
|
+
* Exit code matrix matches {@link exitFromIpcResult}.
|
|
599
|
+
*/
|
|
600
|
+
export function exitCodeFromIpcResult(r: { statusCode?: number }): number {
|
|
601
|
+
if (r.statusCode === undefined) return 10;
|
|
602
|
+
if (r.statusCode >= 500) return 3;
|
|
603
|
+
if (r.statusCode >= 400) return 2;
|
|
604
|
+
return 1;
|
|
503
605
|
}
|
|
@@ -229,6 +229,63 @@ describe("LiveVoiceSession STT", () => {
|
|
|
229
229
|
]);
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
+
test("retains transcriber handle when stop() throws so close() can clean up", async () => {
|
|
233
|
+
class ThrowingStopTranscriber extends MockStreamingTranscriber {
|
|
234
|
+
stopCalls = 0;
|
|
235
|
+
override stop(): void {
|
|
236
|
+
this.stopCalls += 1;
|
|
237
|
+
if (this.stopCalls === 1) {
|
|
238
|
+
throw new Error("stop failed");
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const transcriber = new ThrowingStopTranscriber();
|
|
244
|
+
const { frames, session } = createSessionWithTranscriber(transcriber);
|
|
245
|
+
|
|
246
|
+
await session.start();
|
|
247
|
+
await session.handleClientFrame({ type: "ptt_release" });
|
|
248
|
+
|
|
249
|
+
expect(transcriber.stopCalls).toBe(1);
|
|
250
|
+
expect(
|
|
251
|
+
frames.some(
|
|
252
|
+
(frame) =>
|
|
253
|
+
frame.type === "error" &&
|
|
254
|
+
frame.message.includes(
|
|
255
|
+
"Live voice transcription could not be stopped",
|
|
256
|
+
),
|
|
257
|
+
),
|
|
258
|
+
).toBe(true);
|
|
259
|
+
|
|
260
|
+
await session.close("websocket_close");
|
|
261
|
+
|
|
262
|
+
expect(transcriber.stopCalls).toBe(2);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test("retains transcriber handle when stop() throws so interrupt() can clean up", async () => {
|
|
266
|
+
class ThrowingStopTranscriber extends MockStreamingTranscriber {
|
|
267
|
+
stopCalls = 0;
|
|
268
|
+
override stop(): void {
|
|
269
|
+
this.stopCalls += 1;
|
|
270
|
+
if (this.stopCalls === 1) {
|
|
271
|
+
throw new Error("stop failed");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const transcriber = new ThrowingStopTranscriber();
|
|
277
|
+
const { session } = createSessionWithTranscriber(transcriber);
|
|
278
|
+
|
|
279
|
+
await session.start();
|
|
280
|
+
await session.handleClientFrame({ type: "ptt_release" });
|
|
281
|
+
|
|
282
|
+
expect(transcriber.stopCalls).toBe(1);
|
|
283
|
+
|
|
284
|
+
await session.handleClientFrame({ type: "interrupt" });
|
|
285
|
+
|
|
286
|
+
expect(transcriber.stopCalls).toBe(2);
|
|
287
|
+
});
|
|
288
|
+
|
|
232
289
|
test("uses the production streaming transcriber resolver by default", () => {
|
|
233
290
|
const source = readFileSync(
|
|
234
291
|
new URL("../live-voice-session.ts", import.meta.url),
|
package/src/mcp/client.ts
CHANGED
|
@@ -14,6 +14,24 @@ const log = getLogger("mcp-client");
|
|
|
14
14
|
|
|
15
15
|
const CONNECT_TIMEOUT_MS = 30_000;
|
|
16
16
|
|
|
17
|
+
// MCP servers occasionally return tools with a missing or non-object
|
|
18
|
+
// `inputSchema` (spec violation, but seen in the wild). Coerce to a valid
|
|
19
|
+
// empty object schema so downstream code that assumes `input_schema: object`
|
|
20
|
+
// (e.g. `injectActivityField`) doesn't crash.
|
|
21
|
+
function normalizeInputSchema(
|
|
22
|
+
raw: unknown,
|
|
23
|
+
toolName: string,
|
|
24
|
+
): Record<string, unknown> {
|
|
25
|
+
if (raw != null && typeof raw === "object" && !Array.isArray(raw)) {
|
|
26
|
+
return raw as Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
log.warn(
|
|
29
|
+
{ toolName, received: typeof raw },
|
|
30
|
+
"MCP tool returned non-object inputSchema; defaulting to empty object schema",
|
|
31
|
+
);
|
|
32
|
+
return { type: "object", properties: {} };
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
export interface McpToolInfo {
|
|
18
36
|
name: string;
|
|
19
37
|
description: string;
|
|
@@ -80,9 +98,7 @@ export class McpClient {
|
|
|
80
98
|
`mcp:${this.serverId}:tokens`,
|
|
81
99
|
);
|
|
82
100
|
if (cachedTokens) {
|
|
83
|
-
const callbackTransport = getIsPlatform()
|
|
84
|
-
? "gateway"
|
|
85
|
-
: "loopback";
|
|
101
|
+
const callbackTransport = getIsPlatform() ? "gateway" : "loopback";
|
|
86
102
|
this.oauthProvider = new McpOAuthProvider(
|
|
87
103
|
this.serverId,
|
|
88
104
|
transportConfig.url,
|
|
@@ -164,7 +180,7 @@ export class McpClient {
|
|
|
164
180
|
return result.tools.map((tool) => ({
|
|
165
181
|
name: tool.name,
|
|
166
182
|
description: tool.description ?? "",
|
|
167
|
-
inputSchema: tool.inputSchema
|
|
183
|
+
inputSchema: normalizeInputSchema(tool.inputSchema, tool.name),
|
|
168
184
|
}));
|
|
169
185
|
}
|
|
170
186
|
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* credentials are unavailable.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { resolveManagedProxyContext } from "../providers/
|
|
11
|
+
import { PLATFORM_PROVIDER_META } from "../providers/platform-proxy/constants.js";
|
|
12
|
+
import { resolveManagedProxyContext } from "../providers/platform-proxy/context.js";
|
|
13
13
|
import { getProviderKeyAsync } from "../security/secure-keys.js";
|
|
14
14
|
import type { ImageGenCredentials, ImageGenProvider } from "./types.js";
|
|
15
15
|
|
|
@@ -33,7 +33,7 @@ export async function resolveImageGenCredentials(opts: {
|
|
|
33
33
|
// Resolve platform URL + assistant API key from a single snapshot so
|
|
34
34
|
// baseUrl and assistantApiKey can't diverge if the credential is cleared
|
|
35
35
|
// between lookups.
|
|
36
|
-
const meta =
|
|
36
|
+
const meta = PLATFORM_PROVIDER_META[provider];
|
|
37
37
|
const ctx = await resolveManagedProxyContext();
|
|
38
38
|
if (
|
|
39
39
|
!meta?.managed ||
|
|
@@ -93,17 +93,13 @@ describe("bookmark-crud", () => {
|
|
|
93
93
|
messageId: "msg-1",
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
const first = createBookmark(db, {
|
|
97
|
-
|
|
98
|
-
conversationId: "conv-1",
|
|
99
|
-
});
|
|
100
|
-
const second = createBookmark(db, {
|
|
101
|
-
messageId: "msg-1",
|
|
102
|
-
conversationId: "conv-1",
|
|
103
|
-
});
|
|
96
|
+
const first = createBookmark(db, { messageId: "msg-1" });
|
|
97
|
+
const second = createBookmark(db, { messageId: "msg-1" });
|
|
104
98
|
|
|
105
|
-
expect(
|
|
106
|
-
expect(second.
|
|
99
|
+
expect(first.inserted).toBe(true);
|
|
100
|
+
expect(second.inserted).toBe(false);
|
|
101
|
+
expect(second.bookmark.id).toBe(first.bookmark.id);
|
|
102
|
+
expect(second.bookmark.createdAt).toBe(first.bookmark.createdAt);
|
|
107
103
|
|
|
108
104
|
const all = listBookmarks(db);
|
|
109
105
|
expect(all.length).toBe(1);
|
|
@@ -119,11 +115,10 @@ describe("bookmark-crud", () => {
|
|
|
119
115
|
messageRole: "assistant",
|
|
120
116
|
});
|
|
121
117
|
|
|
122
|
-
const
|
|
123
|
-
messageId: "msg-summary",
|
|
124
|
-
conversationId: "conv-summary",
|
|
125
|
-
});
|
|
118
|
+
const result = createBookmark(db, { messageId: "msg-summary" });
|
|
126
119
|
|
|
120
|
+
expect(result.inserted).toBe(true);
|
|
121
|
+
const summary = result.bookmark;
|
|
127
122
|
expect(summary.conversationTitle).toBe("Title goes here");
|
|
128
123
|
expect(summary.messagePreview).toBe("summary body");
|
|
129
124
|
expect(summary.messageRole).toBe("assistant");
|
|
@@ -179,14 +174,8 @@ describe("bookmark-crud", () => {
|
|
|
179
174
|
conversationId: "conv-drop",
|
|
180
175
|
messageId: "msg-drop",
|
|
181
176
|
});
|
|
182
|
-
createBookmark(db, {
|
|
183
|
-
|
|
184
|
-
conversationId: "conv-keep",
|
|
185
|
-
});
|
|
186
|
-
createBookmark(db, {
|
|
187
|
-
messageId: "msg-drop",
|
|
188
|
-
conversationId: "conv-drop",
|
|
189
|
-
});
|
|
177
|
+
createBookmark(db, { messageId: "msg-keep" });
|
|
178
|
+
createBookmark(db, { messageId: "msg-drop" });
|
|
190
179
|
expect(listBookmarks(db).length).toBe(2);
|
|
191
180
|
|
|
192
181
|
// Deleting the parent conversation cascades through messages → bookmarks.
|
|
@@ -203,7 +192,7 @@ describe("bookmark-crud", () => {
|
|
|
203
192
|
conversationId: "conv-d",
|
|
204
193
|
messageId: "msg-d",
|
|
205
194
|
});
|
|
206
|
-
createBookmark(db, { messageId: "msg-d"
|
|
195
|
+
createBookmark(db, { messageId: "msg-d" });
|
|
207
196
|
expect(listBookmarks(db).length).toBe(1);
|
|
208
197
|
|
|
209
198
|
expect(deleteBookmarkByMessageId(db, "msg-d")).toBe(true);
|
|
@@ -223,9 +212,8 @@ describe("bookmark-crud", () => {
|
|
|
223
212
|
messageRole: "user",
|
|
224
213
|
});
|
|
225
214
|
|
|
226
|
-
const summary = createBookmark(db, {
|
|
215
|
+
const { bookmark: summary } = createBookmark(db, {
|
|
227
216
|
messageId: "msg-blocks",
|
|
228
|
-
conversationId: "conv-blocks",
|
|
229
217
|
});
|
|
230
218
|
|
|
231
219
|
// Without the decode step, this would render as the raw JSON literal
|
|
@@ -248,11 +236,29 @@ describe("bookmark-crud", () => {
|
|
|
248
236
|
messageRole: "assistant",
|
|
249
237
|
});
|
|
250
238
|
|
|
251
|
-
const summary = createBookmark(db, {
|
|
239
|
+
const { bookmark: summary } = createBookmark(db, {
|
|
252
240
|
messageId: "msg-multi",
|
|
253
|
-
conversationId: "conv-multi",
|
|
254
241
|
});
|
|
255
242
|
|
|
256
243
|
expect(summary.messagePreview).toBe("first paragraph\nsecond paragraph");
|
|
257
244
|
});
|
|
245
|
+
|
|
246
|
+
test("createBookmark derives conversationId from the message row", () => {
|
|
247
|
+
const { db, raw } = setupDb();
|
|
248
|
+
seedConversationAndMessage(raw, {
|
|
249
|
+
conversationId: "conv-real",
|
|
250
|
+
messageId: "msg-x",
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const { bookmark: summary } = createBookmark(db, { messageId: "msg-x" });
|
|
254
|
+
expect(summary.conversationId).toBe("conv-real");
|
|
255
|
+
expect(listBookmarks(db)[0]?.conversationId).toBe("conv-real");
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("createBookmark throws when the message id does not exist", () => {
|
|
259
|
+
const { db } = setupDb();
|
|
260
|
+
expect(() => createBookmark(db, { messageId: "ghost" })).toThrow(
|
|
261
|
+
/Message ghost not found/,
|
|
262
|
+
);
|
|
263
|
+
});
|
|
258
264
|
});
|