@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
|
@@ -11,11 +11,7 @@ import { eq } from "drizzle-orm";
|
|
|
11
11
|
|
|
12
12
|
import type { DrizzleDb } from "../db-connection.js";
|
|
13
13
|
import { activationState } from "../schema.js";
|
|
14
|
-
import {
|
|
15
|
-
type ActivationState,
|
|
16
|
-
ActivationStateSchema,
|
|
17
|
-
type EverInjectedEntry,
|
|
18
|
-
} from "./types.js";
|
|
14
|
+
import { type ActivationState, ActivationStateSchema } from "./types.js";
|
|
19
15
|
|
|
20
16
|
/**
|
|
21
17
|
* Load the activation state for a conversation, or `null` if no row exists.
|
|
@@ -123,16 +119,18 @@ export function forkActivationState(
|
|
|
123
119
|
}
|
|
124
120
|
|
|
125
121
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
122
|
+
* Clear all `everInjected` entries. Used after compaction: the cached
|
|
123
|
+
* `<memory>` attachments those slugs lived on are gone, so future turns
|
|
124
|
+
* should be free to re-inject them.
|
|
125
|
+
*
|
|
126
|
+
* Unconditionally empties the list rather than filtering by turn number.
|
|
127
|
+
* `everInjected` is persisted on every turn while the in-memory tracker's
|
|
128
|
+
* `currentTurn` is only snapshotted on graceful conversation dispose, so a
|
|
129
|
+
* non-graceful shutdown (SIGKILL, crash) followed by a reload can leave
|
|
130
|
+
* `everInjected` entries with `turn` values above the restored tracker's
|
|
131
|
+
* `currentTurn`. A turn-bounded filter misses those stale entries and they
|
|
132
|
+
* dedupe forever; a full clear is robust to that drift.
|
|
129
133
|
*/
|
|
130
|
-
export function
|
|
131
|
-
state:
|
|
132
|
-
upToTurn: number,
|
|
133
|
-
): ActivationState {
|
|
134
|
-
const everInjected: EverInjectedEntry[] = state.everInjected.filter(
|
|
135
|
-
(entry) => entry.turn > upToTurn,
|
|
136
|
-
);
|
|
137
|
-
return { ...state, everInjected };
|
|
134
|
+
export function clearEverInjected(state: ActivationState): ActivationState {
|
|
135
|
+
return { ...state, everInjected: [] };
|
|
138
136
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render the prose-style capability statement embedded into the unified
|
|
3
|
+
* `memory_v2_concept_pages` Qdrant collection (under the `cli-commands/<name>`
|
|
4
|
+
* slug prefix). Mirrors `buildSkillContent` in shape — a short prose lead-in
|
|
5
|
+
* followed by the dense capability material — so activation scoring weighs
|
|
6
|
+
* both natural-language intent and structured help text.
|
|
7
|
+
*
|
|
8
|
+
* Intentionally uncapped: CLI `--help` output averages 1–2 KB and the longest
|
|
9
|
+
* (browser, oauth) hits ~3.4 KB. The embedding backend handles inputs of this
|
|
10
|
+
* size without trouble, and trimming would drop the very examples and flag
|
|
11
|
+
* descriptions that make commands semantically findable.
|
|
12
|
+
*/
|
|
13
|
+
export function buildCliCommandContent(
|
|
14
|
+
name: string,
|
|
15
|
+
description: string,
|
|
16
|
+
helpText: string,
|
|
17
|
+
): string {
|
|
18
|
+
return `The "assistant ${name}" CLI command is available. ${description}.\n\nFull help:\n${helpText}`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory v2 — `assistant` CLI subcommands → embedded capability entries
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Enumerate the top-level `assistant` CLI subcommands, render each as a prose
|
|
6
|
+
// capability statement that wraps the full `helpInformation()` output, embed
|
|
7
|
+
// dense + sparse, and upsert into `memory_v2_concept_pages` under the slug
|
|
8
|
+
// `cli-commands/<name>`. The router scores these alongside concept pages and
|
|
9
|
+
// skill entries; the injection layer surfaces hits under `### CLI Commands
|
|
10
|
+
// You Can Use` so the model can semantically discover a CLI capability it
|
|
11
|
+
// would not otherwise know to reach for.
|
|
12
|
+
//
|
|
13
|
+
// Mirrors `skill-store.ts` deliberately: same single-flight + generation
|
|
14
|
+
// coalescing, same dense + sparse + corpus-stats-aware sparse encoding, same
|
|
15
|
+
// payload-kind discriminator, same atomic cache replacement. Differences:
|
|
16
|
+
// - No remote catalog — the source of truth is the local Commander tree.
|
|
17
|
+
// - No per-entry feature-flag filter — flag gating already happens during
|
|
18
|
+
// `buildCliProgramTree` (e.g. email/plugins commands are conditionally
|
|
19
|
+
// registered).
|
|
20
|
+
// - No MCP-style augmentation — Commander's description is the canonical
|
|
21
|
+
// summary.
|
|
22
|
+
|
|
23
|
+
import { getConfig } from "../../config/loader.js";
|
|
24
|
+
import { getLogger } from "../../util/logger.js";
|
|
25
|
+
import { applyCorrectionIfCalibrated } from "../anisotropy.js";
|
|
26
|
+
import {
|
|
27
|
+
embedWithBackend,
|
|
28
|
+
generateSparseEmbedding,
|
|
29
|
+
} from "../embedding-backend.js";
|
|
30
|
+
import { buildCliCommandContent } from "./cli-command-content.js";
|
|
31
|
+
import { invalidatePageIndex } from "./page-index.js";
|
|
32
|
+
import {
|
|
33
|
+
backfillKindOnPointsWithPrefix,
|
|
34
|
+
pruneSlugsWithPrefixExcept,
|
|
35
|
+
upsertConceptPageEmbedding,
|
|
36
|
+
} from "./qdrant.js";
|
|
37
|
+
import {
|
|
38
|
+
generateBm25DocEmbedding,
|
|
39
|
+
getConceptPageCorpusStats,
|
|
40
|
+
} from "./sparse-bm25.js";
|
|
41
|
+
import type { CliCommandEntry } from "./types.js";
|
|
42
|
+
|
|
43
|
+
const log = getLogger("memory-v2-cli-command-store");
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Slug prefix under which CLI-command embeddings are indexed in
|
|
47
|
+
* `memory_v2_concept_pages`. Concept-page slugs must match
|
|
48
|
+
* `[a-z0-9][a-z0-9-]*(/...)*`, and `cli-commands` matches that pattern, so the
|
|
49
|
+
* prefix coexists with hand-authored concept pages without escape work.
|
|
50
|
+
*/
|
|
51
|
+
export const CLI_COMMAND_SLUG_PREFIX = "cli-commands/";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Payload discriminator written on every CLI-command-seeded Qdrant point.
|
|
55
|
+
* Keeps CLI rows distinguishable from user-authored concept pages and from
|
|
56
|
+
* skill rows that happen to live in adjacent namespaces, so prefix pruning
|
|
57
|
+
* never deletes a hand-authored page sitting under `cli-commands/...`.
|
|
58
|
+
*/
|
|
59
|
+
const CLI_COMMAND_PAYLOAD_KIND = "cli-command";
|
|
60
|
+
|
|
61
|
+
/** Compose the unified-collection slug for a CLI command name. */
|
|
62
|
+
export function cliCommandSlugFor(name: string): string {
|
|
63
|
+
return `${CLI_COMMAND_SLUG_PREFIX}${name}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Module-level cache of rendered CLI-command entries keyed by command name.
|
|
68
|
+
* `null` until the first successful seed run completes; replaced atomically
|
|
69
|
+
* on each successful re-seed so callers always see a consistent snapshot.
|
|
70
|
+
*/
|
|
71
|
+
let entries: Map<string, CliCommandEntry> | null = null;
|
|
72
|
+
let requestedSeedGeneration = 0;
|
|
73
|
+
let processedSeedGeneration = 0;
|
|
74
|
+
let activeSeedDrain: Promise<void> | null = null;
|
|
75
|
+
let lastSeedError: unknown = null;
|
|
76
|
+
const seedWaiters: Array<{ generation: number; resolve: () => void }> = [];
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* In-process latch for the legacy `kind` backfill. New upserts always write
|
|
80
|
+
* `kind`, so once the latch is set there is no follow-up work to do this
|
|
81
|
+
* process.
|
|
82
|
+
*/
|
|
83
|
+
let legacyKindBackfillDone = false;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Seed (or re-seed) CLI-command embeddings into the unified concept-page
|
|
87
|
+
* collection. Idempotent. Best-effort for background callers (errors are
|
|
88
|
+
* logged but swallowed); pass `{ throwOnError: true }` from synchronous CLI
|
|
89
|
+
* paths that want failures surfaced.
|
|
90
|
+
*
|
|
91
|
+
* Single-flight + coalesced: at most one seed runs at a time. Requests made
|
|
92
|
+
* while a seed is in flight advance the requested generation; stale in-flight
|
|
93
|
+
* snapshots are skipped before they write embeddings or replace the cache.
|
|
94
|
+
*/
|
|
95
|
+
export async function seedV2CliCommandEntries(
|
|
96
|
+
opts: { throwOnError?: boolean } = {},
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
const generation = ++requestedSeedGeneration;
|
|
99
|
+
const waiter = new Promise<void>((resolve) => {
|
|
100
|
+
seedWaiters.push({ generation, resolve });
|
|
101
|
+
});
|
|
102
|
+
startSeedDrainIfNeeded();
|
|
103
|
+
await waiter;
|
|
104
|
+
if (opts.throwOnError && lastSeedError) {
|
|
105
|
+
throw lastSeedError;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function startSeedDrainIfNeeded(): void {
|
|
110
|
+
if (activeSeedDrain) return;
|
|
111
|
+
if (processedSeedGeneration >= requestedSeedGeneration) return;
|
|
112
|
+
|
|
113
|
+
activeSeedDrain = drainSeedQueue().finally(() => {
|
|
114
|
+
activeSeedDrain = null;
|
|
115
|
+
startSeedDrainIfNeeded();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function drainSeedQueue(): Promise<void> {
|
|
120
|
+
while (processedSeedGeneration < requestedSeedGeneration) {
|
|
121
|
+
const generationToProcess = requestedSeedGeneration;
|
|
122
|
+
await runSeedV2CliCommandEntries(generationToProcess);
|
|
123
|
+
processedSeedGeneration = generationToProcess;
|
|
124
|
+
resolveSeedWaiters();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function resolveSeedWaiters(): void {
|
|
129
|
+
for (let i = seedWaiters.length - 1; i >= 0; i -= 1) {
|
|
130
|
+
const waiter = seedWaiters[i]!;
|
|
131
|
+
if (waiter.generation > processedSeedGeneration) continue;
|
|
132
|
+
seedWaiters.splice(i, 1);
|
|
133
|
+
waiter.resolve();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function runSeedV2CliCommandEntries(generation: number): Promise<void> {
|
|
138
|
+
try {
|
|
139
|
+
const config = getConfig();
|
|
140
|
+
// Dynamic import so callers that only need `getCliCommandCapability` or
|
|
141
|
+
// `listCliCommandEntries` (e.g. the render path inside `injection.ts` and
|
|
142
|
+
// the `page-index.ts` dependency loader) never drag the full CLI command
|
|
143
|
+
// graph into their import tree. The CLI tree pulls in many provider and
|
|
144
|
+
// workspace modules whose presence has been a recurring source of test-
|
|
145
|
+
// mock cascades and circular-import surprises.
|
|
146
|
+
const { buildCliProgramTree } = await import("../../cli/program.js");
|
|
147
|
+
const program = buildCliProgramTree();
|
|
148
|
+
|
|
149
|
+
const seeds: CliCommandEntry[] = [];
|
|
150
|
+
for (const cmd of program.commands) {
|
|
151
|
+
const name = cmd.name();
|
|
152
|
+
// Skip the `help` builtin Commander adds automatically — it carries no
|
|
153
|
+
// capability information of its own and is uniform across commands.
|
|
154
|
+
if (name === "help") continue;
|
|
155
|
+
const description = cmd.description();
|
|
156
|
+
const content = buildCliCommandContent(
|
|
157
|
+
name,
|
|
158
|
+
description,
|
|
159
|
+
cmd.helpInformation(),
|
|
160
|
+
);
|
|
161
|
+
seeds.push({ id: name, description, content });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const nextEntries = new Map<string, CliCommandEntry>();
|
|
165
|
+
let denseVectors: number[][] = [];
|
|
166
|
+
let encodeSparse: (
|
|
167
|
+
input: string,
|
|
168
|
+
) => ReturnType<typeof generateSparseEmbedding> = generateSparseEmbedding;
|
|
169
|
+
if (seeds.length > 0) {
|
|
170
|
+
const embedded = await embedWithBackend(
|
|
171
|
+
config,
|
|
172
|
+
seeds.map((s) => s.content),
|
|
173
|
+
);
|
|
174
|
+
denseVectors = await Promise.all(
|
|
175
|
+
embedded.vectors.map((v) =>
|
|
176
|
+
applyCorrectionIfCalibrated(v, embedded.provider, embedded.model),
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// CLI commands share the concept-page Qdrant collection, so the sparse
|
|
181
|
+
// vector must use the same stemmed BM25 encoding as the concept-page
|
|
182
|
+
// documents. Fall back to the legacy TF encoder only during the cold-
|
|
183
|
+
// start window before corpus stats finish building — same rationale as
|
|
184
|
+
// the skill-store path.
|
|
185
|
+
const corpusStats = getConceptPageCorpusStats();
|
|
186
|
+
encodeSparse = (input: string) =>
|
|
187
|
+
corpusStats
|
|
188
|
+
? generateBm25DocEmbedding(input, corpusStats, {
|
|
189
|
+
k1: config.memory.v2.bm25_k1,
|
|
190
|
+
b: config.memory.v2.bm25_b,
|
|
191
|
+
})
|
|
192
|
+
: generateSparseEmbedding(input);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (generation !== requestedSeedGeneration) {
|
|
196
|
+
log.info(
|
|
197
|
+
{ generation, latestGeneration: requestedSeedGeneration },
|
|
198
|
+
"Skipping stale v2 CLI-command seed result",
|
|
199
|
+
);
|
|
200
|
+
lastSeedError = null;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (seeds.length > 0) {
|
|
205
|
+
const now = Date.now();
|
|
206
|
+
await Promise.all(
|
|
207
|
+
seeds.map((seed, i) =>
|
|
208
|
+
upsertConceptPageEmbedding({
|
|
209
|
+
slug: cliCommandSlugFor(seed.id),
|
|
210
|
+
dense: denseVectors[i],
|
|
211
|
+
sparse: encodeSparse(seed.content),
|
|
212
|
+
updatedAt: now,
|
|
213
|
+
kind: CLI_COMMAND_PAYLOAD_KIND,
|
|
214
|
+
}),
|
|
215
|
+
),
|
|
216
|
+
);
|
|
217
|
+
for (const seed of seeds) {
|
|
218
|
+
nextEntries.set(seed.id, seed);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// The CLI tree is always available (no remote catalog), so pruning is
|
|
223
|
+
// unconditional. Run the legacy `kind` backfill once per process so
|
|
224
|
+
// pre-discriminator rows become prunable.
|
|
225
|
+
const knownIds = new Set(seeds.map((s) => s.id));
|
|
226
|
+
if (!legacyKindBackfillDone) {
|
|
227
|
+
try {
|
|
228
|
+
await backfillKindOnPointsWithPrefix(
|
|
229
|
+
CLI_COMMAND_SLUG_PREFIX,
|
|
230
|
+
CLI_COMMAND_PAYLOAD_KIND,
|
|
231
|
+
knownIds,
|
|
232
|
+
);
|
|
233
|
+
legacyKindBackfillDone = true;
|
|
234
|
+
} catch (err) {
|
|
235
|
+
log.warn(
|
|
236
|
+
{ err },
|
|
237
|
+
"Failed to backfill kind on legacy CLI-command points — pruning may leave orphans this run",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
await pruneSlugsWithPrefixExcept(
|
|
242
|
+
CLI_COMMAND_SLUG_PREFIX,
|
|
243
|
+
seeds.map((s) => s.id),
|
|
244
|
+
{ kind: CLI_COMMAND_PAYLOAD_KIND },
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
// Atomically replace the cache only after every step above succeeds.
|
|
248
|
+
entries = nextEntries;
|
|
249
|
+
invalidatePageIndex();
|
|
250
|
+
lastSeedError = null;
|
|
251
|
+
} catch (err) {
|
|
252
|
+
lastSeedError = err;
|
|
253
|
+
log.warn({ err }, "Failed to seed v2 CLI-command entries");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Synchronous lookup of a previously-seeded `CliCommandEntry` by command
|
|
259
|
+
* name. Returns `null` when the cache has not yet been populated, when the
|
|
260
|
+
* id is unknown, or when a prior seed run dropped the id.
|
|
261
|
+
*
|
|
262
|
+
* Accepts either a bare command name (`attachment`) or its unified-collection
|
|
263
|
+
* slug (`cli-commands/attachment`) so render-side callers can pass through
|
|
264
|
+
* what they have without a manual prefix strip.
|
|
265
|
+
*
|
|
266
|
+
* Returns a frozen copy so callers cannot mutate the underlying cache entry.
|
|
267
|
+
*/
|
|
268
|
+
export function getCliCommandCapability(
|
|
269
|
+
idOrSlug: string,
|
|
270
|
+
): CliCommandEntry | null {
|
|
271
|
+
const id = idOrSlug.startsWith(CLI_COMMAND_SLUG_PREFIX)
|
|
272
|
+
? idOrSlug.slice(CLI_COMMAND_SLUG_PREFIX.length)
|
|
273
|
+
: idOrSlug;
|
|
274
|
+
const entry = entries?.get(id);
|
|
275
|
+
return entry ? Object.freeze({ ...entry }) : null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** True iff the slug refers to a CLI-command entry in the unified collection. */
|
|
279
|
+
export function isCliCommandSlug(slug: string): boolean {
|
|
280
|
+
return slug.startsWith(CLI_COMMAND_SLUG_PREFIX);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Snapshot of the in-process CLI-command cache, sorted by command name (ASCII
|
|
285
|
+
* order) for determinism. Returns a freshly allocated array of frozen entry
|
|
286
|
+
* copies on each call.
|
|
287
|
+
*/
|
|
288
|
+
export function listCliCommandEntries(): CliCommandEntry[] {
|
|
289
|
+
if (!entries) return [];
|
|
290
|
+
return [...entries.values()]
|
|
291
|
+
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
|
|
292
|
+
.map((entry) => Object.freeze({ ...entry }));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** @internal Test-only: clear the module-level cache. */
|
|
296
|
+
export function _resetCliCommandStoreForTests(): void {
|
|
297
|
+
entries = null;
|
|
298
|
+
requestedSeedGeneration = 0;
|
|
299
|
+
processedSeedGeneration = 0;
|
|
300
|
+
activeSeedDrain = null;
|
|
301
|
+
seedWaiters.splice(0, seedWaiters.length);
|
|
302
|
+
lastSeedError = null;
|
|
303
|
+
legacyKindBackfillDone = false;
|
|
304
|
+
}
|
|
@@ -22,6 +22,7 @@ import { join } from "node:path";
|
|
|
22
22
|
|
|
23
23
|
import { parse as parseYaml } from "yaml";
|
|
24
24
|
|
|
25
|
+
import type { AssistantConfig } from "../../config/schema.js";
|
|
25
26
|
import { FRONTMATTER_REGEX } from "../../skills/frontmatter.js";
|
|
26
27
|
import { getLogger } from "../../util/logger.js";
|
|
27
28
|
import { listPages } from "./page-store.js";
|
|
@@ -32,11 +33,16 @@ const log = getLogger("memory-v2-frontmatter-sweep");
|
|
|
32
33
|
/**
|
|
33
34
|
* Validate every concept page's frontmatter against the strict schema and
|
|
34
35
|
* emit a `warn` per offender. Never throws — daemon startup must not block
|
|
35
|
-
* on this safety net.
|
|
36
|
+
* on this safety net. Self-gates on `config.memory.v2.enabled`: when v2
|
|
37
|
+
* is off, concept pages never enter a retrieval top-K so any warns here
|
|
38
|
+
* would be pure noise.
|
|
36
39
|
*/
|
|
37
40
|
export async function sweepConceptPageFrontmatter(
|
|
41
|
+
config: AssistantConfig,
|
|
38
42
|
workspaceDir: string,
|
|
39
43
|
): Promise<void> {
|
|
44
|
+
if (!config.memory.v2.enabled) return;
|
|
45
|
+
|
|
40
46
|
let slugs: string[];
|
|
41
47
|
try {
|
|
42
48
|
slugs = await listPages(workspaceDir);
|
|
@@ -38,6 +38,10 @@ import {
|
|
|
38
38
|
spreadActivation,
|
|
39
39
|
} from "./activation.js";
|
|
40
40
|
import { hydrate, save } from "./activation-store.js";
|
|
41
|
+
import {
|
|
42
|
+
getCliCommandCapability,
|
|
43
|
+
isCliCommandSlug,
|
|
44
|
+
} from "./cli-command-store.js";
|
|
41
45
|
import { getEdgeIndex } from "./edge-index.js";
|
|
42
46
|
import { readPage, renderPageContent } from "./page-store.js";
|
|
43
47
|
import { runRouter } from "./router.js";
|
|
@@ -144,6 +148,7 @@ export async function injectMemoryV2Block(
|
|
|
144
148
|
} = params;
|
|
145
149
|
|
|
146
150
|
const workspaceDir = getWorkspaceDir();
|
|
151
|
+
const mode: InjectMemoryV2Mode = params.mode ?? "per-turn";
|
|
147
152
|
|
|
148
153
|
// (1) Hydrate. Missing rows are normal at conversation start — proceed
|
|
149
154
|
// with an effective empty prior state so the first turn can still inject.
|
|
@@ -151,10 +156,17 @@ export async function injectMemoryV2Block(
|
|
|
151
156
|
const priorState = await hydrate(database, conversationId);
|
|
152
157
|
|
|
153
158
|
// Flag-gated router dispatch: when the LLM router is enabled, route the
|
|
154
|
-
//
|
|
155
|
-
//
|
|
159
|
+
// page selection through `runRouter` and reuse `finalizeInjection` for
|
|
160
|
+
// persistence, render, and telemetry. The activation pipeline below
|
|
156
161
|
// remains the default (flag-off) behavior — every code path past this
|
|
157
162
|
// branch only runs when the router is disabled.
|
|
163
|
+
//
|
|
164
|
+
// Runs on both `per-turn` and `context-load`. The `everInjected` dedupe
|
|
165
|
+
// concern from earlier doesn't apply post-compaction because
|
|
166
|
+
// `evictCompactedTurnsV2` in `ConversationGraphMemory.onCompacted`
|
|
167
|
+
// empties the list before this code runs. Router abstention on
|
|
168
|
+
// context-load means no v2 pages restored that turn, which is preferable
|
|
169
|
+
// to letting the activation graph pick something arbitrary.
|
|
158
170
|
if (config.memory.v2.router.enabled) {
|
|
159
171
|
return injectViaRouter({
|
|
160
172
|
workspaceDir,
|
|
@@ -214,7 +226,6 @@ export async function injectMemoryV2Block(
|
|
|
214
226
|
// prior cached attachments don't exist or have been thrown away. The user
|
|
215
227
|
// message gets a complete top-K dump alongside the static
|
|
216
228
|
// essentials/threads/recent block, then per-turn turns just add deltas.
|
|
217
|
-
const mode: InjectMemoryV2Mode = params.mode ?? "per-turn";
|
|
218
229
|
const priorEverInjected: readonly EverInjectedEntry[] =
|
|
219
230
|
priorState?.everInjected ?? [];
|
|
220
231
|
const { topNow, toInject } = selectInjections({
|
|
@@ -310,6 +321,14 @@ async function finalizeInjection(args: {
|
|
|
310
321
|
telemetryRows: MemoryV2ConceptRowRecord[];
|
|
311
322
|
config: AssistantConfig;
|
|
312
323
|
nextStateMap: Record<string, number>;
|
|
324
|
+
/**
|
|
325
|
+
* When true, errors thrown inside the helper (save / render / status
|
|
326
|
+
* finalization) are logged and swallowed instead of re-thrown. Used by
|
|
327
|
+
* the router-failure path, which is already a best-effort cleanup: a
|
|
328
|
+
* transient SQLite write here must not abort the turn on top of the
|
|
329
|
+
* router failure that already happened. Defaults to throwing.
|
|
330
|
+
*/
|
|
331
|
+
bestEffort?: boolean;
|
|
313
332
|
}): Promise<InjectMemoryV2BlockResult> {
|
|
314
333
|
const {
|
|
315
334
|
workspaceDir,
|
|
@@ -340,20 +359,22 @@ async function finalizeInjection(args: {
|
|
|
340
359
|
// on that user message and the agent keeps seeing it across subsequent turns
|
|
341
360
|
// until compaction evicts the turn.
|
|
342
361
|
//
|
|
343
|
-
//
|
|
344
|
-
// between the
|
|
345
|
-
// at an uninstalled skill
|
|
346
|
-
// per-turn runs re-attempt attachment
|
|
347
|
-
// this, the slug would be marked
|
|
348
|
-
// silently dropped it.
|
|
349
|
-
const
|
|
362
|
+
// Synthetic slugs (skills, CLI commands) whose in-process cache entry is
|
|
363
|
+
// missing (e.g. startup race between the seed and the first turn, or stale
|
|
364
|
+
// Qdrant index pointing at an uninstalled skill / removed CLI command) are
|
|
365
|
+
// excluded from `everInjected` so future per-turn runs re-attempt attachment
|
|
366
|
+
// once the cache is populated. Without this, the slug would be marked
|
|
367
|
+
// injected even though `renderInjectionBlock` silently dropped it.
|
|
368
|
+
const missingSyntheticSlugs = new Set(
|
|
350
369
|
slugsToRender.filter(
|
|
351
|
-
(slug) =>
|
|
370
|
+
(slug) =>
|
|
371
|
+
(isSkillSlug(slug) && !getSkillCapability(slug)) ||
|
|
372
|
+
(isCliCommandSlug(slug) && !getCliCommandCapability(slug)),
|
|
352
373
|
),
|
|
353
374
|
);
|
|
354
375
|
const everInjectedSet = new Set(priorEverInjected.map((entry) => entry.slug));
|
|
355
376
|
const newlyInjected = slugsToRender.filter(
|
|
356
|
-
(slug) => !everInjectedSet.has(slug) && !
|
|
377
|
+
(slug) => !everInjectedSet.has(slug) && !missingSyntheticSlugs.has(slug),
|
|
357
378
|
);
|
|
358
379
|
const nextEverInjected: EverInjectedEntry[] = [
|
|
359
380
|
...priorEverInjected,
|
|
@@ -449,9 +470,16 @@ async function finalizeInjection(args: {
|
|
|
449
470
|
} catch (err) {
|
|
450
471
|
// Stash the error and let `finally` flush a best-effort telemetry row
|
|
451
472
|
// before we re-throw to the caller. `mode = "errored"` flags the row
|
|
452
|
-
// for observability dashboards / inspector queries.
|
|
473
|
+
// for observability dashboards / inspector queries. On the best-effort
|
|
474
|
+
// path the error is logged and swallowed so the trailing return stands.
|
|
453
475
|
caughtErr = err;
|
|
454
476
|
mode = "errored";
|
|
477
|
+
if (args.bestEffort) {
|
|
478
|
+
log.warn(
|
|
479
|
+
{ err, conversationId, turn: currentTurn },
|
|
480
|
+
"Memory v2 finalizeInjection error on best-effort path — swallowing",
|
|
481
|
+
);
|
|
482
|
+
}
|
|
455
483
|
} finally {
|
|
456
484
|
try {
|
|
457
485
|
recordMemoryV2ActivationLog({
|
|
@@ -469,7 +497,7 @@ async function finalizeInjection(args: {
|
|
|
469
497
|
}
|
|
470
498
|
}
|
|
471
499
|
|
|
472
|
-
if (caughtErr !== undefined) throw caughtErr;
|
|
500
|
+
if (caughtErr !== undefined && !args.bestEffort) throw caughtErr;
|
|
473
501
|
return { block, toInject: newlyInjected };
|
|
474
502
|
}
|
|
475
503
|
|
|
@@ -537,7 +565,10 @@ async function injectViaRouter(args: {
|
|
|
537
565
|
// (preserving `priorEverInjected` so future turns still subtract
|
|
538
566
|
// previously-attached slugs) and writes the telemetry row through the
|
|
539
567
|
// same code path as the success branch — no inline duplication of
|
|
540
|
-
// `save` + `recordMemoryV2ActivationLog`.
|
|
568
|
+
// `save` + `recordMemoryV2ActivationLog`. `bestEffort: true` matches
|
|
569
|
+
// the pre-refactor inline behavior of logging and continuing if the
|
|
570
|
+
// stub-state `save()` throws — we don't want a transient SQLite write
|
|
571
|
+
// to abort the turn on top of the router failure that already happened.
|
|
541
572
|
return finalizeInjection({
|
|
542
573
|
workspaceDir,
|
|
543
574
|
database,
|
|
@@ -550,6 +581,7 @@ async function injectViaRouter(args: {
|
|
|
550
581
|
telemetryRows: [],
|
|
551
582
|
config,
|
|
552
583
|
nextStateMap: {},
|
|
584
|
+
bestEffort: true,
|
|
553
585
|
});
|
|
554
586
|
}
|
|
555
587
|
|
|
@@ -702,18 +734,18 @@ const INJECTION_HEADER =
|
|
|
702
734
|
* distinguish "file vanished" (stale index) from "file is malformed"
|
|
703
735
|
* (data-corruption / programmer error).
|
|
704
736
|
*
|
|
705
|
-
* Skill slugs whose entry the cache no longer
|
|
706
|
-
* mid-run
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
*
|
|
710
|
-
* bug.
|
|
737
|
+
* Skill and CLI-command slugs whose entry the in-process cache no longer
|
|
738
|
+
* knows (e.g. uninstalled mid-run, or a CLI command removed between seeds)
|
|
739
|
+
* are silently dropped, mirroring the missing-pages behavior but without
|
|
740
|
+
* entering `missingSlugs` — the synthetic catalogs are the source of truth
|
|
741
|
+
* for those entries, not on-disk concept pages.
|
|
711
742
|
*
|
|
712
743
|
* Each concept-page section is rendered as a path header followed by either
|
|
713
744
|
* the page's `summary` (when present in frontmatter) or the full page (the
|
|
714
|
-
* fallback for pages predating the summary field). Skills sit
|
|
715
|
-
* under `### Skills You Can Use`,
|
|
716
|
-
*
|
|
745
|
+
* fallback for pages predating the summary field). Skills sit after the
|
|
746
|
+
* concept sections under `### Skills You Can Use`, and CLI subcommands sit
|
|
747
|
+
* after the skills under `### CLI Commands You Can Use`. The leading
|
|
748
|
+
* `**CRITICAL:**` line tells the agent how to read the block.
|
|
717
749
|
*
|
|
718
750
|
* **CRITICAL:** These are page summaries. Read the page file if it looks relevant.
|
|
719
751
|
*
|
|
@@ -732,13 +764,24 @@ const INJECTION_HEADER =
|
|
|
732
764
|
* ### Skills You Can Use
|
|
733
765
|
* - <skill-1 content>
|
|
734
766
|
* - <skill-2 content>
|
|
767
|
+
*
|
|
768
|
+
* ### CLI Commands You Can Use
|
|
769
|
+
* Run `assistant <command> --help` for full usage.
|
|
770
|
+
* - `assistant <name-1>`: <description-1>
|
|
771
|
+
* - `assistant <name-2>`: <description-2>
|
|
735
772
|
*/
|
|
736
773
|
async function renderInjectionBlock(
|
|
737
774
|
workspaceDir: string,
|
|
738
775
|
slugs: string[],
|
|
739
776
|
): Promise<RenderInjectionBlockResult> {
|
|
740
|
-
const conceptSlugs =
|
|
741
|
-
const skillSlugs =
|
|
777
|
+
const conceptSlugs: string[] = [];
|
|
778
|
+
const skillSlugs: string[] = [];
|
|
779
|
+
const cliCommandSlugs: string[] = [];
|
|
780
|
+
for (const slug of slugs) {
|
|
781
|
+
if (isSkillSlug(slug)) skillSlugs.push(slug);
|
|
782
|
+
else if (isCliCommandSlug(slug)) cliCommandSlugs.push(slug);
|
|
783
|
+
else conceptSlugs.push(slug);
|
|
784
|
+
}
|
|
742
785
|
|
|
743
786
|
const settled = await Promise.allSettled(
|
|
744
787
|
conceptSlugs.map((slug) => readPage(workspaceDir, slug)),
|
|
@@ -789,6 +832,18 @@ async function renderInjectionBlock(
|
|
|
789
832
|
sections.push(`### Skills You Can Use\n${skillLines.join("\n")}`);
|
|
790
833
|
}
|
|
791
834
|
|
|
835
|
+
const cliCommandLines: string[] = [];
|
|
836
|
+
for (const slug of cliCommandSlugs) {
|
|
837
|
+
const entry = getCliCommandCapability(slug);
|
|
838
|
+
if (!entry) continue;
|
|
839
|
+
cliCommandLines.push(`- \`assistant ${entry.id}\`: ${entry.description}`);
|
|
840
|
+
}
|
|
841
|
+
if (cliCommandLines.length > 0) {
|
|
842
|
+
sections.push(
|
|
843
|
+
`### CLI Commands You Can Use\nRun \`assistant <command> --help\` for full usage.\n${cliCommandLines.join("\n")}`,
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
|
|
792
847
|
if (sections.length === 0) {
|
|
793
848
|
return { block: null, missingSlugs, corruptSlugs };
|
|
794
849
|
}
|