@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
|
@@ -643,12 +643,15 @@ export async function runMemoryV2Migration(
|
|
|
643
643
|
}
|
|
644
644
|
|
|
645
645
|
/**
|
|
646
|
-
* HTML
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
646
|
+
* Paired HTML markers wrapped around each appended block. The opening marker
|
|
647
|
+
* also serves as the idempotency guard: `appendLines` is a read-modify-write,
|
|
648
|
+
* and without it a crash between `appendPromotions` and `writeSentinel` would
|
|
649
|
+
* let the next boot duplicate every promotion line. The closing marker
|
|
650
|
+
* delimits the migration-inserted region so a force-rerun strip can remove
|
|
651
|
+
* exactly that block without touching user/assistant edits appended below.
|
|
650
652
|
*/
|
|
651
|
-
const
|
|
653
|
+
const PROMOTION_MARKER_OPEN = "<!-- migration:v1-to-v2 -->";
|
|
654
|
+
const PROMOTION_MARKER_CLOSE = "<!-- /migration:v1-to-v2 -->";
|
|
652
655
|
|
|
653
656
|
/**
|
|
654
657
|
* Append each promotion bucket to its target file. Files are created if
|
|
@@ -680,8 +683,8 @@ async function appendPromotions(
|
|
|
680
683
|
|
|
681
684
|
/**
|
|
682
685
|
* Append `lines` to `path`, creating it (with a trailing newline) if absent.
|
|
683
|
-
* If the file already contains `
|
|
684
|
-
* prior partially-completed migration already wrote this block.
|
|
686
|
+
* If the file already contains `PROMOTION_MARKER_OPEN`, the append is skipped
|
|
687
|
+
* — a prior partially-completed migration already wrote this block.
|
|
685
688
|
*/
|
|
686
689
|
async function appendLines(path: string, lines: string[]): Promise<void> {
|
|
687
690
|
let existing = "";
|
|
@@ -690,16 +693,17 @@ async function appendLines(path: string, lines: string[]): Promise<void> {
|
|
|
690
693
|
} catch (err) {
|
|
691
694
|
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
|
692
695
|
}
|
|
693
|
-
if (existing.includes(
|
|
696
|
+
if (existing.includes(PROMOTION_MARKER_OPEN)) return;
|
|
694
697
|
const trailing = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
695
|
-
const
|
|
698
|
+
const block = `${PROMOTION_MARKER_OPEN}\n${lines.join("\n")}\n${PROMOTION_MARKER_CLOSE}\n`;
|
|
699
|
+
const next = `${existing}${trailing}${block}`;
|
|
696
700
|
await writeFile(path, next, "utf-8");
|
|
697
701
|
}
|
|
698
702
|
|
|
699
703
|
/**
|
|
700
|
-
* Strip any prior migration-block
|
|
701
|
-
*
|
|
702
|
-
*
|
|
704
|
+
* Strip any prior migration-block from each promotion target. Called on
|
|
705
|
+
* force-reruns so the marker guard in `appendLines` doesn't skip the new
|
|
706
|
+
* promotions.
|
|
703
707
|
*/
|
|
704
708
|
async function stripPromotionMarkerBlocks(workspaceDir: string): Promise<void> {
|
|
705
709
|
const memoryDir = join(workspaceDir, "memory");
|
|
@@ -718,6 +722,16 @@ async function stripPromotionMarkerBlocks(workspaceDir: string): Promise<void> {
|
|
|
718
722
|
await Promise.all(candidates.map(stripMarkerBlock));
|
|
719
723
|
}
|
|
720
724
|
|
|
725
|
+
/**
|
|
726
|
+
* Remove the migration-inserted block from `path` while preserving content
|
|
727
|
+
* outside it. The block is identified by the
|
|
728
|
+
* `PROMOTION_MARKER_OPEN ... PROMOTION_MARKER_CLOSE` envelope.
|
|
729
|
+
*
|
|
730
|
+
* If an opening marker is present without a matching close, strip from the
|
|
731
|
+
* opening marker to the next blank line, or to EOF if none is found. Content
|
|
732
|
+
* appended after such an unclosed block without a blank-line separator can
|
|
733
|
+
* be dropped on that fallback path.
|
|
734
|
+
*/
|
|
721
735
|
async function stripMarkerBlock(path: string): Promise<void> {
|
|
722
736
|
let existing: string;
|
|
723
737
|
try {
|
|
@@ -726,13 +740,29 @@ async function stripMarkerBlock(path: string): Promise<void> {
|
|
|
726
740
|
if ((err as NodeJS.ErrnoException).code === "ENOENT") return;
|
|
727
741
|
throw err;
|
|
728
742
|
}
|
|
729
|
-
const
|
|
730
|
-
if (
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
743
|
+
const openIdx = existing.indexOf(PROMOTION_MARKER_OPEN);
|
|
744
|
+
if (openIdx === -1) return;
|
|
745
|
+
|
|
746
|
+
let endIdx: number;
|
|
747
|
+
const closeIdx = existing.indexOf(PROMOTION_MARKER_CLOSE, openIdx);
|
|
748
|
+
if (closeIdx !== -1) {
|
|
749
|
+
endIdx = closeIdx + PROMOTION_MARKER_CLOSE.length;
|
|
750
|
+
if (existing[endIdx] === "\n") endIdx += 1;
|
|
751
|
+
} else {
|
|
752
|
+
const blankIdx = existing.indexOf("\n\n", openIdx);
|
|
753
|
+
endIdx = blankIdx === -1 ? existing.length : blankIdx + 2;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const head = existing.slice(0, openIdx).replace(/\n+$/, "");
|
|
757
|
+
const tail = existing.slice(endIdx);
|
|
758
|
+
let next: string;
|
|
759
|
+
if (head.length === 0) {
|
|
760
|
+
next = tail;
|
|
761
|
+
} else if (tail.length === 0) {
|
|
762
|
+
next = `${head}\n`;
|
|
763
|
+
} else {
|
|
764
|
+
next = `${head}\n${tail}`;
|
|
765
|
+
}
|
|
736
766
|
await writeFile(path, next, "utf-8");
|
|
737
767
|
}
|
|
738
768
|
|
|
@@ -30,6 +30,16 @@ const log = getLogger("memory-v2-page-index");
|
|
|
30
30
|
|
|
31
31
|
const SUMMARY_MAX_LENGTH = 200;
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Collapse every run of whitespace (including embedded newlines and tabs) to a
|
|
35
|
+
* single space and trim. The router prompt renders one entry per line, so an
|
|
36
|
+
* embedded newline anywhere in `summary` would split that entry across lines
|
|
37
|
+
* and corrupt the format the router parses.
|
|
38
|
+
*/
|
|
39
|
+
function normalizeSummary(raw: string): string {
|
|
40
|
+
return raw.replace(/\s+/g, " ").trim().slice(0, SUMMARY_MAX_LENGTH);
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
/**
|
|
34
44
|
* One row in the rendered page index. `id` is a 1-based dense integer that is
|
|
35
45
|
* stable within a single index version (i.e. a single build). It changes when
|
|
@@ -70,11 +80,12 @@ let cache: CachedIndex | null = null;
|
|
|
70
80
|
/**
|
|
71
81
|
* Return a `PageIndex` for `workspaceDir`. Cached module-locally; the cache
|
|
72
82
|
* is invalidated by `invalidatePageIndex` (called by daemon-side hooks when
|
|
73
|
-
* concept pages or
|
|
83
|
+
* concept pages, skill entries, or CLI-command entries change).
|
|
74
84
|
*
|
|
75
85
|
* Cold builds list every concept page in parallel, drop pages whose read
|
|
76
|
-
* rejects, append seeded skill entries from `listSkillEntries()
|
|
77
|
-
*
|
|
86
|
+
* rejects, append seeded skill entries from `listSkillEntries()` and CLI
|
|
87
|
+
* command entries from `listCliCommandEntries()`, sort by slug for
|
|
88
|
+
* deterministic IDs, then resolve outgoing edges to numeric IDs.
|
|
78
89
|
*/
|
|
79
90
|
export async function getPageIndex(workspaceDir: string): Promise<PageIndex> {
|
|
80
91
|
if (cache && cache.workspaceDir === workspaceDir) {
|
|
@@ -97,6 +108,30 @@ export async function getPageIndex(workspaceDir: string): Promise<PageIndex> {
|
|
|
97
108
|
outgoingSlugs: string[];
|
|
98
109
|
}
|
|
99
110
|
|
|
111
|
+
const [
|
|
112
|
+
{ listSkillEntries, SKILL_SLUG_PREFIX },
|
|
113
|
+
{ listCliCommandEntries, CLI_COMMAND_SLUG_PREFIX },
|
|
114
|
+
] = await Promise.all([
|
|
115
|
+
import("./skill-store.js"),
|
|
116
|
+
import("./cli-command-store.js"),
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
// Build the synthetic-slug sets first so we can drop colliding concept
|
|
120
|
+
// pages. Collision policy: **synthetic entries win**. Skill and CLI rows
|
|
121
|
+
// are seeded from authoritative in-process catalogs; a hand-authored page
|
|
122
|
+
// sitting under `skills/<id>` or `cli-commands/<name>` is either a stale
|
|
123
|
+
// leftover from a prior write or a user mistake. `bySlug` is last-writer-
|
|
124
|
+
// wins, so without explicit dedupe one side would silently shadow the
|
|
125
|
+
// other depending on iteration order.
|
|
126
|
+
const skillEntries = listSkillEntries();
|
|
127
|
+
const skillSlugs = new Set(
|
|
128
|
+
skillEntries.map((entry) => `${SKILL_SLUG_PREFIX}${entry.id}`),
|
|
129
|
+
);
|
|
130
|
+
const cliCommandEntries = listCliCommandEntries();
|
|
131
|
+
const cliCommandSlugs = new Set(
|
|
132
|
+
cliCommandEntries.map((entry) => `${CLI_COMMAND_SLUG_PREFIX}${entry.id}`),
|
|
133
|
+
);
|
|
134
|
+
|
|
100
135
|
const drafts: DraftEntry[] = [];
|
|
101
136
|
for (let i = 0; i < settled.length; i++) {
|
|
102
137
|
const result = settled[i];
|
|
@@ -110,20 +145,40 @@ export async function getPageIndex(workspaceDir: string): Promise<PageIndex> {
|
|
|
110
145
|
}
|
|
111
146
|
const page = result.value;
|
|
112
147
|
if (!page) continue;
|
|
148
|
+
if (skillSlugs.has(slug)) {
|
|
149
|
+
log.warn(
|
|
150
|
+
{ slug },
|
|
151
|
+
"Dropping concept page from index — slug collides with a seeded skill entry; skill wins",
|
|
152
|
+
);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (cliCommandSlugs.has(slug)) {
|
|
156
|
+
log.warn(
|
|
157
|
+
{ slug },
|
|
158
|
+
"Dropping concept page from index — slug collides with a seeded CLI-command entry; CLI command wins",
|
|
159
|
+
);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
113
162
|
const summarySource = page.frontmatter.summary?.trim() || page.body.trim();
|
|
114
163
|
drafts.push({
|
|
115
164
|
slug,
|
|
116
|
-
summary: summarySource
|
|
165
|
+
summary: normalizeSummary(summarySource),
|
|
117
166
|
outgoingSlugs: page.frontmatter.edges,
|
|
118
167
|
});
|
|
119
168
|
}
|
|
120
169
|
|
|
121
|
-
const
|
|
122
|
-
await import("./skill-store.js");
|
|
123
|
-
for (const entry of listSkillEntries()) {
|
|
170
|
+
for (const entry of skillEntries) {
|
|
124
171
|
drafts.push({
|
|
125
172
|
slug: `${SKILL_SLUG_PREFIX}${entry.id}`,
|
|
126
|
-
summary: entry.content
|
|
173
|
+
summary: normalizeSummary(entry.content),
|
|
174
|
+
outgoingSlugs: [],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
for (const entry of cliCommandEntries) {
|
|
179
|
+
drafts.push({
|
|
180
|
+
slug: `${CLI_COMMAND_SLUG_PREFIX}${entry.id}`,
|
|
181
|
+
summary: normalizeSummary(entry.description),
|
|
127
182
|
outgoingSlugs: [],
|
|
128
183
|
});
|
|
129
184
|
}
|
|
@@ -27,7 +27,6 @@ import { homedir } from "node:os";
|
|
|
27
27
|
import { isAbsolute, join } from "node:path";
|
|
28
28
|
|
|
29
29
|
import { getLogger } from "../../../util/logger.js";
|
|
30
|
-
import { getWorkspaceDir } from "../../../util/platform.js";
|
|
31
30
|
|
|
32
31
|
const log = getLogger("memory-v2-router-prompt");
|
|
33
32
|
|
|
@@ -102,7 +101,7 @@ export function renderRouterPrompt(opts: RenderRouterPromptOpts): string {
|
|
|
102
101
|
* referenced by `memory.v2.router.router_prompt_path`, then substitute the
|
|
103
102
|
* standard placeholders. Path-resolution rules mirror the consolidation
|
|
104
103
|
* prompt override: absolute paths used as-is, leading `~/` expanded to home,
|
|
105
|
-
* relative paths resolved under
|
|
104
|
+
* relative paths resolved under `workspaceDir`.
|
|
106
105
|
*
|
|
107
106
|
* Failure handling is intentionally permissive — missing file, read error,
|
|
108
107
|
* oversized file, or empty/whitespace-only body all log a warning and fall
|
|
@@ -111,11 +110,12 @@ export function renderRouterPrompt(opts: RenderRouterPromptOpts): string {
|
|
|
111
110
|
*/
|
|
112
111
|
export function resolveRouterPrompt(
|
|
113
112
|
overridePath: string | null,
|
|
113
|
+
workspaceDir: string,
|
|
114
114
|
opts: RenderRouterPromptOpts,
|
|
115
115
|
): string {
|
|
116
116
|
if (overridePath === null) return renderRouterPrompt(opts);
|
|
117
117
|
|
|
118
|
-
const resolvedPath = resolveOverridePath(overridePath);
|
|
118
|
+
const resolvedPath = resolveOverridePath(overridePath, workspaceDir);
|
|
119
119
|
let contents: string;
|
|
120
120
|
try {
|
|
121
121
|
const stat = lstatSync(resolvedPath);
|
|
@@ -178,15 +178,18 @@ function substitutePlaceholders(
|
|
|
178
178
|
const assistant = opts.assistantName?.trim() || "the assistant";
|
|
179
179
|
const user = opts.userName?.trim() || "the user";
|
|
180
180
|
return template
|
|
181
|
-
.replaceAll(ASSISTANT_NAME_PLACEHOLDER, assistant)
|
|
182
|
-
.replaceAll(USER_NAME_PLACEHOLDER, user)
|
|
183
|
-
.replaceAll(PAGE_INDEX_PLACEHOLDER, opts.pageIndexBlock);
|
|
181
|
+
.replaceAll(ASSISTANT_NAME_PLACEHOLDER, () => assistant)
|
|
182
|
+
.replaceAll(USER_NAME_PLACEHOLDER, () => user)
|
|
183
|
+
.replaceAll(PAGE_INDEX_PLACEHOLDER, () => opts.pageIndexBlock);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
function resolveOverridePath(
|
|
186
|
+
function resolveOverridePath(
|
|
187
|
+
overridePath: string,
|
|
188
|
+
workspaceDir: string,
|
|
189
|
+
): string {
|
|
187
190
|
if (overridePath.startsWith("~/")) {
|
|
188
191
|
return join(homedir(), overridePath.slice(2));
|
|
189
192
|
}
|
|
190
193
|
if (isAbsolute(overridePath)) return overridePath;
|
|
191
|
-
return join(
|
|
194
|
+
return join(workspaceDir, overridePath);
|
|
192
195
|
}
|
|
@@ -51,6 +51,6 @@ export function renderSweepPrompt(opts: {
|
|
|
51
51
|
const user = opts.userName?.trim() || "the user";
|
|
52
52
|
return SWEEP_PROMPT.replaceAll(
|
|
53
53
|
ASSISTANT_NAME_PLACEHOLDER,
|
|
54
|
-
assistant,
|
|
55
|
-
).replaceAll(USER_NAME_PLACEHOLDER, user);
|
|
54
|
+
() => assistant,
|
|
55
|
+
).replaceAll(USER_NAME_PLACEHOLDER, () => user);
|
|
56
56
|
}
|
package/src/memory/v2/qdrant.ts
CHANGED
|
@@ -200,6 +200,9 @@ async function ensureConceptPageCollectionOnce(): Promise<{
|
|
|
200
200
|
|
|
201
201
|
const missing = missingNamedVectors(info);
|
|
202
202
|
if (missing.length === 0) {
|
|
203
|
+
// Long-lived installs may predate the `kind` payload index; ensure
|
|
204
|
+
// every required index exists before declaring the collection ready.
|
|
205
|
+
await ensurePayloadIndexes();
|
|
203
206
|
_collectionReady = true;
|
|
204
207
|
return { migrated: false };
|
|
205
208
|
}
|
|
@@ -271,17 +274,62 @@ async function ensureConceptPageCollectionOnce(): Promise<{
|
|
|
271
274
|
throw err;
|
|
272
275
|
}
|
|
273
276
|
|
|
274
|
-
|
|
275
|
-
// so upserts and slug-restricted queries don't pay a per-call indexing cost.
|
|
276
|
-
await client.createPayloadIndex(MEMORY_V2_COLLECTION, {
|
|
277
|
-
field_name: "slug",
|
|
278
|
-
field_schema: "keyword",
|
|
279
|
-
});
|
|
277
|
+
await ensurePayloadIndexes();
|
|
280
278
|
|
|
281
279
|
_collectionReady = true;
|
|
282
280
|
return { migrated };
|
|
283
281
|
}
|
|
284
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Idempotently create the payload indexes the collection's query and
|
|
285
|
+
* filter paths rely on:
|
|
286
|
+
*
|
|
287
|
+
* - `slug` (keyword): every slug-restricted query and prefix scan filters on it.
|
|
288
|
+
* - `kind` (keyword): the skill-backfill scroll filters with `is_empty` on
|
|
289
|
+
* `kind`. Strict-mode Qdrant deployments reject filters on unindexed
|
|
290
|
+
* payload fields, so without this the backfill consistently fails and
|
|
291
|
+
* legacy skill points remain untagged.
|
|
292
|
+
*
|
|
293
|
+
* Same-schema `createPayloadIndex` calls are idempotent server-side in
|
|
294
|
+
* Qdrant (200 OK), so the only "already exists" failures we expect are
|
|
295
|
+
* narrow races where a concurrent caller created the same index a moment
|
|
296
|
+
* earlier. Those are benign and swallowed. Every other failure — strict-mode
|
|
297
|
+
* rejection, index-limit, transient network blip — must propagate so the
|
|
298
|
+
* caller does not latch readiness on a collection whose `slug`/`kind`
|
|
299
|
+
* filters will keep rejecting queries until the next daemon restart.
|
|
300
|
+
*/
|
|
301
|
+
async function ensurePayloadIndexes(): Promise<void> {
|
|
302
|
+
const client = getClient();
|
|
303
|
+
const indexes = [
|
|
304
|
+
{ field_name: "slug", field_schema: "keyword" as const },
|
|
305
|
+
{ field_name: "kind", field_schema: "keyword" as const },
|
|
306
|
+
];
|
|
307
|
+
// Parallel so one "already exists" race on a single index doesn't stall
|
|
308
|
+
// the other create round-trip. v1's `qdrant-client.ts` uses the same
|
|
309
|
+
// Promise.all shape.
|
|
310
|
+
await Promise.all(
|
|
311
|
+
indexes.map(async (index) => {
|
|
312
|
+
try {
|
|
313
|
+
await client.createPayloadIndex(MEMORY_V2_COLLECTION, index);
|
|
314
|
+
} catch (err) {
|
|
315
|
+
if (isPayloadIndexAlreadyExists(err)) return;
|
|
316
|
+
throw err;
|
|
317
|
+
}
|
|
318
|
+
}),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* True when a `createPayloadIndex` error indicates the index already
|
|
324
|
+
* exists with matching parameters — the only failure shape it is safe to
|
|
325
|
+
* swallow. Qdrant returns 4xx with messages like
|
|
326
|
+
* `"Wrong input: Payload field 'kind' already exists ..."`.
|
|
327
|
+
*/
|
|
328
|
+
function isPayloadIndexAlreadyExists(err: unknown): boolean {
|
|
329
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
330
|
+
return /already exists/i.test(msg);
|
|
331
|
+
}
|
|
332
|
+
|
|
285
333
|
/**
|
|
286
334
|
* Return the names of required named vectors absent from the collection's
|
|
287
335
|
* current schema. An empty array means the collection is fully migrated.
|
|
@@ -422,7 +470,10 @@ export async function deleteConceptPageEmbedding(slug: string): Promise<void> {
|
|
|
422
470
|
* `payload.kind` matches are eligible for deletion. This is critical because
|
|
423
471
|
* `validateSlug` permits user-authored concept pages slugged like
|
|
424
472
|
* `skills/foo`; without a kind filter they would collide with the skill
|
|
425
|
-
* namespace and be repeatedly pruned every seed run.
|
|
473
|
+
* namespace and be repeatedly pruned every seed run. The companion
|
|
474
|
+
* {@link backfillKindOnPointsWithPrefix} preserves this invariant for legacy
|
|
475
|
+
* untagged rows by tagging only suffixes the caller knows are skills —
|
|
476
|
+
* user-authored `skills/<slug>` rows stay kindless and outside this prune.
|
|
426
477
|
*
|
|
427
478
|
* Idempotent: when the live `<prefix>*` slugs already match `activeSuffixes`,
|
|
428
479
|
* the function performs a single scroll and no deletes.
|
|
@@ -491,6 +542,83 @@ export async function pruneSlugsWithPrefixExcept(
|
|
|
491
542
|
}
|
|
492
543
|
}
|
|
493
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Set `payload.kind` on every point whose slug starts with `prefix`, whose
|
|
547
|
+
* suffix is in `allowedSuffixes`, and is currently missing the `kind`
|
|
548
|
+
* discriminator. Used to tag legacy rows that predate the kind field so the
|
|
549
|
+
* kind-scoped {@link pruneSlugsWithPrefixExcept} no longer leaves them as
|
|
550
|
+
* orphans.
|
|
551
|
+
*
|
|
552
|
+
* `allowedSuffixes` is required because `validateSlug` permits user-authored
|
|
553
|
+
* concept pages slugged like `skills/my-notes` — those rows also lack `kind`
|
|
554
|
+
* and would otherwise be tagged here and then deleted by the kind-scoped
|
|
555
|
+
* prune. Callers must pass the closed set of legitimate suffixes (e.g. the
|
|
556
|
+
* union of installed + remote-catalog skill IDs) so user pages stay untagged.
|
|
557
|
+
*
|
|
558
|
+
* The "missing kind" predicate is pushed to Qdrant via `is_empty`, so once
|
|
559
|
+
* every legacy row has been tagged the scroll returns the bounded set of
|
|
560
|
+
* other kindless concept pages without ever touching the already-tagged
|
|
561
|
+
* rows. Idempotent across retries: a row tagged by an earlier partial run
|
|
562
|
+
* no longer matches the filter and is silently skipped.
|
|
563
|
+
*/
|
|
564
|
+
export async function backfillKindOnPointsWithPrefix(
|
|
565
|
+
prefix: string,
|
|
566
|
+
kind: string,
|
|
567
|
+
allowedSuffixes: ReadonlySet<string>,
|
|
568
|
+
): Promise<number> {
|
|
569
|
+
if (allowedSuffixes.size === 0) return 0;
|
|
570
|
+
await ensureConceptPageCollection();
|
|
571
|
+
|
|
572
|
+
const client = getClient();
|
|
573
|
+
|
|
574
|
+
const doBackfill = async (): Promise<number> => {
|
|
575
|
+
const pointIds: Array<string | number> = [];
|
|
576
|
+
let offset: string | number | undefined = undefined;
|
|
577
|
+
const maxIterations = 10_000;
|
|
578
|
+
const batchSize = 256;
|
|
579
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
580
|
+
const result = await client.scroll(MEMORY_V2_COLLECTION, {
|
|
581
|
+
limit: batchSize,
|
|
582
|
+
with_payload: true,
|
|
583
|
+
with_vector: false,
|
|
584
|
+
filter: { must: [{ is_empty: { key: "kind" } }] },
|
|
585
|
+
...(offset !== undefined ? { offset } : {}),
|
|
586
|
+
});
|
|
587
|
+
for (const point of result.points) {
|
|
588
|
+
const slug = (point.payload as { slug?: unknown } | null)?.slug;
|
|
589
|
+
if (typeof slug !== "string") continue;
|
|
590
|
+
if (!slug.startsWith(prefix)) continue;
|
|
591
|
+
const suffix = slug.slice(prefix.length);
|
|
592
|
+
if (!allowedSuffixes.has(suffix)) continue;
|
|
593
|
+
pointIds.push(point.id);
|
|
594
|
+
}
|
|
595
|
+
const next = result.next_page_offset;
|
|
596
|
+
if (next == null) break;
|
|
597
|
+
offset = typeof next === "string" ? next : (next as number);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (pointIds.length === 0) return 0;
|
|
601
|
+
|
|
602
|
+
await client.setPayload(MEMORY_V2_COLLECTION, {
|
|
603
|
+
payload: { kind },
|
|
604
|
+
points: pointIds,
|
|
605
|
+
wait: true,
|
|
606
|
+
});
|
|
607
|
+
return pointIds.length;
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
try {
|
|
611
|
+
return await doBackfill();
|
|
612
|
+
} catch (err) {
|
|
613
|
+
if (isCollectionMissing(err)) {
|
|
614
|
+
_collectionReady = false;
|
|
615
|
+
await ensureConceptPageCollection();
|
|
616
|
+
return await doBackfill();
|
|
617
|
+
}
|
|
618
|
+
throw err;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
494
622
|
/**
|
|
495
623
|
* Approximate count of points in the v2 concept-page collection. Used by the
|
|
496
624
|
* daemon-startup rebuild hook to detect "collection exists but empty" — the
|
package/src/memory/v2/router.ts
CHANGED
|
@@ -181,6 +181,7 @@ export async function runRouter(
|
|
|
181
181
|
|
|
182
182
|
const systemPrompt = resolveRouterPrompt(
|
|
183
183
|
config.memory?.v2?.router?.router_prompt_path ?? null,
|
|
184
|
+
workspaceDir,
|
|
184
185
|
{
|
|
185
186
|
assistantName: getAssistantName(),
|
|
186
187
|
userName: resolveUserName(workspaceDir),
|
|
@@ -274,22 +275,22 @@ export async function runRouter(
|
|
|
274
275
|
);
|
|
275
276
|
}
|
|
276
277
|
|
|
277
|
-
|
|
278
|
-
|
|
278
|
+
// De-duplicate BEFORE applying the cap — otherwise a duplicate-heavy
|
|
279
|
+
// model output like `[1, 1, 2]` with `max=2` slices to `[1, 1]` and
|
|
280
|
+
// dedupes to `[1]`, under-filling the cap.
|
|
281
|
+
const dedupedIds = Array.from(new Set(inRangeIds));
|
|
282
|
+
|
|
283
|
+
const truncated = dedupedIds.length > maxPageIds;
|
|
284
|
+
const finalIds = truncated ? dedupedIds.slice(0, maxPageIds) : dedupedIds;
|
|
279
285
|
if (truncated) {
|
|
280
286
|
log.warn(
|
|
281
|
-
{ returned:
|
|
287
|
+
{ returned: dedupedIds.length, max: maxPageIds },
|
|
282
288
|
"Router returned more page IDs than max_page_ids; truncating",
|
|
283
289
|
);
|
|
284
290
|
}
|
|
285
291
|
|
|
286
|
-
// De-duplicate while preserving order — the index lookup alone wouldn't
|
|
287
|
-
// catch repeats from the model.
|
|
288
|
-
const seen = new Set<number>();
|
|
289
292
|
const selectedSlugs: string[] = [];
|
|
290
293
|
for (const id of finalIds) {
|
|
291
|
-
if (seen.has(id)) continue;
|
|
292
|
-
seen.add(id);
|
|
293
294
|
const entry = pageIndex.byId.get(id);
|
|
294
295
|
if (!entry) continue;
|
|
295
296
|
selectedSlugs.push(entry.slug);
|