@vellumai/assistant 0.8.7 → 0.8.8
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/Dockerfile +20 -4
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/plugins.md +75 -79
- package/examples/plugins/echo/README.md +6 -12
- package/examples/plugins/echo/register.ts +0 -41
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/openapi.yaml +3381 -348
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +34 -39
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-pipeline.test.ts +1 -1
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +313 -1136
- package/src/__tests__/conversation-agent-loop.test.ts +596 -1616
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +26 -5
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +170 -229
- package/src/__tests__/conversation-runtime-workspace.test.ts +3 -24
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +2 -8
- package/src/__tests__/injector-chain.test.ts +106 -270
- package/src/__tests__/injector-disk-pressure.test.ts +3 -12
- package/src/__tests__/injector-document-comments.test.ts +2 -2
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pipeline-runner.test.ts +29 -39
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-bootstrap.test.ts +13 -28
- package/src/__tests__/plugin-registry.test.ts +0 -27
- package/src/__tests__/plugin-types.test.ts +2 -125
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +2 -2
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/agent/loop.ts +346 -442
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +368 -0
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -20
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +35 -3
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +122 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +3 -6
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +605 -153
- package/src/daemon/conversation-agent-loop.ts +281 -760
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-runtime-assembly.ts +130 -347
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation.ts +32 -14
- package/src/daemon/external-plugins-bootstrap.ts +9 -10
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +39 -10
- package/src/daemon/lifecycle.ts +4 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +4 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +31 -4
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -1
- package/src/memory/v2/consolidation-job.ts +1 -1
- package/src/memory/v3/__tests__/health.test.ts +16 -0
- package/src/memory/v3/__tests__/orchestrate.test.ts +45 -9
- package/src/memory/v3/__tests__/provider-blocks.test.ts +13 -0
- package/src/memory/v3/__tests__/router.test.ts +101 -29
- package/src/memory/v3/__tests__/selector.test.ts +93 -27
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +23 -5
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/llm-retry.ts +32 -0
- package/src/memory/v3/orchestrate.ts +26 -14
- package/src/memory/v3/provider-blocks.ts +15 -5
- package/src/memory/v3/router.ts +48 -42
- package/src/memory/v3/selector.ts +57 -42
- package/src/memory/v3/shadow-plugin.ts +47 -15
- package/src/memory/v3/types.ts +8 -0
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +8 -1
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +1 -15
- package/src/plugins/defaults/injectors/register.ts +243 -74
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +91 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/pipeline.ts +6 -18
- package/src/plugins/registry.ts +8 -25
- package/src/plugins/types.ts +43 -474
- package/src/proactive-artifact/aux-message-injector.ts +3 -3
- package/src/proactive-artifact/job.test.ts +7 -12
- package/src/prompts/__tests__/system-prompt.test.ts +36 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +62 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +5 -1
- package/src/runtime/agent-wake.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-query-routes.ts +2 -0
- package/src/runtime/routes/conversation-routes.ts +358 -184
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +208 -17
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +50 -28
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/executor.ts +1 -53
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +9 -1
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +93 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/package.json +0 -15
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
4
|
|
|
3
5
|
// This test exercises v1 PKB injection. `config.memory.v2.enabled` (default
|
|
4
6
|
// `true`) makes the PKB injector go silent — force it off here so the v1
|
|
@@ -44,7 +46,6 @@ import {
|
|
|
44
46
|
assembleSlackChronologicalMessages,
|
|
45
47
|
buildSubagentStatusBlock,
|
|
46
48
|
buildUnifiedTurnContextBlock,
|
|
47
|
-
findLastInjectedNowContent,
|
|
48
49
|
getSlackCompactionWatermarkForPrefix,
|
|
49
50
|
injectChannelCapabilityContext,
|
|
50
51
|
injectChannelCommandContext,
|
|
@@ -60,29 +61,47 @@ import {
|
|
|
60
61
|
} from "../daemon/conversation-runtime-assembly.js";
|
|
61
62
|
import { buildPkbReminder } from "../daemon/pkb-reminder-builder.js";
|
|
62
63
|
import type { MessageRow } from "../memory/conversation-crud.js";
|
|
64
|
+
import { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
65
|
+
import { getPkbRoot } from "../memory/pkb/types.js";
|
|
63
66
|
import {
|
|
64
67
|
type SlackMessageMetadata,
|
|
65
68
|
writeSlackMetadata,
|
|
66
69
|
} from "../messaging/providers/slack/message-metadata.js";
|
|
67
70
|
import { parentAlias } from "../messaging/providers/slack/render-transcript.js";
|
|
68
|
-
import { defaultInjectorsPlugin } from "../plugins/defaults/injectors/register.js";
|
|
69
|
-
import {
|
|
70
|
-
registerPlugin,
|
|
71
|
-
resetPluginRegistryForTests,
|
|
72
|
-
} from "../plugins/registry.js";
|
|
73
71
|
import type { Message } from "../providers/types.js";
|
|
74
72
|
import { wrapUntrustedContent } from "../security/untrusted-content.js";
|
|
75
73
|
import type { SubagentState } from "../subagent/types.js";
|
|
74
|
+
import { getWorkspacePromptPath } from "../util/platform.js";
|
|
75
|
+
|
|
76
|
+
// The pkb-reminder injector derives PKB-active state from the workspace itself
|
|
77
|
+
// — `readPkbContext()` returning content behind the personal-memory trust gate
|
|
78
|
+
// — rather than from a threaded flag. Tests that need the reminder to fire seed
|
|
79
|
+
// a default auto-injected PKB file under the workspace pkb root; tests that
|
|
80
|
+
// need it suppressed leave the pkb dir empty.
|
|
81
|
+
function seedPkbContent(): void {
|
|
82
|
+
const root = getPkbRoot();
|
|
83
|
+
mkdirSync(root, { recursive: true });
|
|
84
|
+
writeFileSync(join(root, "INDEX.md"), "workspace knowledge index", "utf-8");
|
|
85
|
+
}
|
|
76
86
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
function clearPkbContent(): void {
|
|
88
|
+
rmSync(getPkbRoot(), { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// The now-md injector derives NOW.md state from the workspace itself —
|
|
92
|
+
// `readNowScratchpad()` returning content behind the personal-memory trust gate
|
|
93
|
+
// and the `scratchpadInjection` config toggle — rather than from a threaded
|
|
94
|
+
// option. Seed the file so the injector fires; clear it so suites that assert
|
|
95
|
+
// NOW.md is absent stay unaffected.
|
|
96
|
+
function seedNowScratchpad(content: string): void {
|
|
97
|
+
const nowPath = getWorkspacePromptPath("NOW.md");
|
|
98
|
+
mkdirSync(dirname(nowPath), { recursive: true });
|
|
99
|
+
writeFileSync(nowPath, content, "utf-8");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function clearNowScratchpad(): void {
|
|
103
|
+
rmSync(getWorkspacePromptPath("NOW.md"), { force: true });
|
|
104
|
+
}
|
|
86
105
|
|
|
87
106
|
// ---------------------------------------------------------------------------
|
|
88
107
|
// resolveChannelCapabilities
|
|
@@ -748,12 +767,33 @@ describe("applyRuntimeInjections — injection mode", () => {
|
|
|
748
767
|
} as ChannelCapabilities,
|
|
749
768
|
unifiedTurnContext:
|
|
750
769
|
"<turn_context>\ncurrent_time: 2026-03-04 (Tuesday) 12:00:00 +00:00 (UTC)\ninterface: telegram\n</turn_context>",
|
|
751
|
-
nowScratchpad: "Current focus: shipping PR 3",
|
|
752
|
-
pkbContext: "essentials content here",
|
|
753
|
-
pkbActive: true,
|
|
754
770
|
isNonInteractive: true,
|
|
771
|
+
// Guardian trust so the personal-memory gate admits the actor regardless
|
|
772
|
+
// of the telegram channel capabilities under test, letting the reminder
|
|
773
|
+
// gate hinge purely on PKB content presence.
|
|
774
|
+
turnContext: {
|
|
775
|
+
requestId: "injection-mode-req",
|
|
776
|
+
conversationId: "injection-mode-conv",
|
|
777
|
+
turnIndex: 0,
|
|
778
|
+
trust: {
|
|
779
|
+
sourceChannel: "vellum" as const,
|
|
780
|
+
trustClass: "guardian" as const,
|
|
781
|
+
},
|
|
782
|
+
},
|
|
755
783
|
};
|
|
756
784
|
|
|
785
|
+
// The reminder fires only when the workspace has PKB content, and the now-md
|
|
786
|
+
// injector only when NOW.md has content; seed both so the full-mode cases
|
|
787
|
+
// exercise the active branch.
|
|
788
|
+
beforeEach(() => {
|
|
789
|
+
seedPkbContent();
|
|
790
|
+
seedNowScratchpad("Current focus: shipping PR 3");
|
|
791
|
+
});
|
|
792
|
+
afterEach(() => {
|
|
793
|
+
clearPkbContent();
|
|
794
|
+
clearNowScratchpad();
|
|
795
|
+
});
|
|
796
|
+
|
|
757
797
|
test("full mode (default) includes all injections", async () => {
|
|
758
798
|
const { messages: result } = await applyRuntimeInjections(
|
|
759
799
|
baseMessages,
|
|
@@ -860,12 +900,10 @@ describe("applyRuntimeInjections — injection mode", () => {
|
|
|
860
900
|
});
|
|
861
901
|
});
|
|
862
902
|
|
|
863
|
-
// The
|
|
864
|
-
//
|
|
865
|
-
//
|
|
866
|
-
//
|
|
867
|
-
// nowScratchpad` and the injection-mode tests) cover that behaviour
|
|
868
|
-
// end-to-end.
|
|
903
|
+
// The now-md default injector emits the `<NOW.md>` block as an
|
|
904
|
+
// `after-memory-prefix` placement during `applyRuntimeInjections`. The suites
|
|
905
|
+
// below (`applyRuntimeInjections with nowScratchpad` and the injection-mode
|
|
906
|
+
// tests) cover that behaviour end-to-end.
|
|
869
907
|
|
|
870
908
|
// ---------------------------------------------------------------------------
|
|
871
909
|
// stripNowScratchpad
|
|
@@ -1192,10 +1230,14 @@ describe("applyRuntimeInjections with nowScratchpad", () => {
|
|
|
1192
1230
|
},
|
|
1193
1231
|
];
|
|
1194
1232
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1233
|
+
// The now-md injector sources NOW.md from the workspace itself rather than
|
|
1234
|
+
// from a threaded option, so seed the file to drive injection and clear it so
|
|
1235
|
+
// the absent-content cases see no block.
|
|
1236
|
+
afterEach(clearNowScratchpad);
|
|
1237
|
+
|
|
1238
|
+
test("injects NOW.md block when the file has content", async () => {
|
|
1239
|
+
seedNowScratchpad("Current focus: fix the bug");
|
|
1240
|
+
const { messages: result } = await applyRuntimeInjections(baseMessages, {});
|
|
1199
1241
|
|
|
1200
1242
|
expect(result.length).toBe(1);
|
|
1201
1243
|
expect(result[0].content.length).toBe(2);
|
|
@@ -1206,9 +1248,8 @@ describe("applyRuntimeInjections with nowScratchpad", () => {
|
|
|
1206
1248
|
});
|
|
1207
1249
|
|
|
1208
1250
|
test("scratchpad appears before user's original text content", async () => {
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
});
|
|
1251
|
+
seedNowScratchpad("scratchpad notes");
|
|
1252
|
+
const { messages: result } = await applyRuntimeInjections(baseMessages, {});
|
|
1212
1253
|
|
|
1213
1254
|
// Scratchpad comes first (before user content)
|
|
1214
1255
|
expect(
|
|
@@ -1220,16 +1261,7 @@ describe("applyRuntimeInjections with nowScratchpad", () => {
|
|
|
1220
1261
|
);
|
|
1221
1262
|
});
|
|
1222
1263
|
|
|
1223
|
-
test("does not inject when
|
|
1224
|
-
const { messages: result } = await applyRuntimeInjections(baseMessages, {
|
|
1225
|
-
nowScratchpad: null,
|
|
1226
|
-
});
|
|
1227
|
-
|
|
1228
|
-
expect(result.length).toBe(1);
|
|
1229
|
-
expect(result[0].content.length).toBe(1);
|
|
1230
|
-
});
|
|
1231
|
-
|
|
1232
|
-
test("does not inject when nowScratchpad is omitted", async () => {
|
|
1264
|
+
test("does not inject when the NOW.md file is absent", async () => {
|
|
1233
1265
|
const { messages: result } = await applyRuntimeInjections(baseMessages, {});
|
|
1234
1266
|
|
|
1235
1267
|
expect(result.length).toBe(1);
|
|
@@ -1237,8 +1269,8 @@ describe("applyRuntimeInjections with nowScratchpad", () => {
|
|
|
1237
1269
|
});
|
|
1238
1270
|
|
|
1239
1271
|
test("skipped in minimal mode", async () => {
|
|
1272
|
+
seedNowScratchpad("Current focus: fix the bug");
|
|
1240
1273
|
const { messages: result } = await applyRuntimeInjections(baseMessages, {
|
|
1241
|
-
nowScratchpad: "Current focus: fix the bug",
|
|
1242
1274
|
mode: "minimal",
|
|
1243
1275
|
});
|
|
1244
1276
|
|
|
@@ -1782,85 +1814,6 @@ describe("applyRuntimeInjections blocks.unifiedTurnContext", () => {
|
|
|
1782
1814
|
});
|
|
1783
1815
|
});
|
|
1784
1816
|
|
|
1785
|
-
// ---------------------------------------------------------------------------
|
|
1786
|
-
// findLastInjectedNowContent
|
|
1787
|
-
// ---------------------------------------------------------------------------
|
|
1788
|
-
|
|
1789
|
-
describe("findLastInjectedNowContent", () => {
|
|
1790
|
-
test("extracts NOW.md content from the last user message", () => {
|
|
1791
|
-
const messages: Message[] = [
|
|
1792
|
-
{
|
|
1793
|
-
role: "user",
|
|
1794
|
-
content: [
|
|
1795
|
-
{
|
|
1796
|
-
type: "text",
|
|
1797
|
-
text: "<NOW.md Always keep this up to date>\nCurrent focus: fix the bug\n</NOW.md>",
|
|
1798
|
-
},
|
|
1799
|
-
{ type: "text", text: "Hello" },
|
|
1800
|
-
],
|
|
1801
|
-
},
|
|
1802
|
-
];
|
|
1803
|
-
|
|
1804
|
-
expect(findLastInjectedNowContent(messages)).toBe(
|
|
1805
|
-
"Current focus: fix the bug",
|
|
1806
|
-
);
|
|
1807
|
-
});
|
|
1808
|
-
|
|
1809
|
-
test("returns null when no NOW.md injection exists", () => {
|
|
1810
|
-
const messages: Message[] = [
|
|
1811
|
-
{
|
|
1812
|
-
role: "user",
|
|
1813
|
-
content: [{ type: "text", text: "Hello" }],
|
|
1814
|
-
},
|
|
1815
|
-
];
|
|
1816
|
-
|
|
1817
|
-
expect(findLastInjectedNowContent(messages)).toBeNull();
|
|
1818
|
-
});
|
|
1819
|
-
|
|
1820
|
-
test("returns the most recent injection when multiple exist", () => {
|
|
1821
|
-
const messages: Message[] = [
|
|
1822
|
-
{
|
|
1823
|
-
role: "user",
|
|
1824
|
-
content: [
|
|
1825
|
-
{
|
|
1826
|
-
type: "text",
|
|
1827
|
-
text: "<NOW.md Always keep this up to date>\nOld focus\n</NOW.md>",
|
|
1828
|
-
},
|
|
1829
|
-
],
|
|
1830
|
-
},
|
|
1831
|
-
{ role: "assistant", content: [{ type: "text", text: "OK" }] },
|
|
1832
|
-
{
|
|
1833
|
-
role: "user",
|
|
1834
|
-
content: [
|
|
1835
|
-
{
|
|
1836
|
-
type: "text",
|
|
1837
|
-
text: "<NOW.md Always keep this up to date>\nNew focus\n</NOW.md>",
|
|
1838
|
-
},
|
|
1839
|
-
],
|
|
1840
|
-
},
|
|
1841
|
-
];
|
|
1842
|
-
|
|
1843
|
-
expect(findLastInjectedNowContent(messages)).toBe("New focus");
|
|
1844
|
-
});
|
|
1845
|
-
|
|
1846
|
-
test("skips assistant messages", () => {
|
|
1847
|
-
const messages: Message[] = [
|
|
1848
|
-
{
|
|
1849
|
-
role: "user",
|
|
1850
|
-
content: [
|
|
1851
|
-
{
|
|
1852
|
-
type: "text",
|
|
1853
|
-
text: "<NOW.md Always keep this up to date>\nUser focus\n</NOW.md>",
|
|
1854
|
-
},
|
|
1855
|
-
],
|
|
1856
|
-
},
|
|
1857
|
-
{ role: "assistant", content: [{ type: "text", text: "response" }] },
|
|
1858
|
-
];
|
|
1859
|
-
|
|
1860
|
-
expect(findLastInjectedNowContent(messages)).toBe("User focus");
|
|
1861
|
-
});
|
|
1862
|
-
});
|
|
1863
|
-
|
|
1864
1817
|
// ---------------------------------------------------------------------------
|
|
1865
1818
|
// Subagent status injection
|
|
1866
1819
|
// ---------------------------------------------------------------------------
|
|
@@ -2032,21 +1985,33 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2032
1985
|
|
|
2033
1986
|
const FLAT_REMINDER = buildPkbReminder([]);
|
|
2034
1987
|
|
|
2035
|
-
//
|
|
2036
|
-
//
|
|
2037
|
-
//
|
|
2038
|
-
const
|
|
2039
|
-
|
|
1988
|
+
// The pkb-reminder injector sources the PKB root itself via `getPkbRoot()`,
|
|
1989
|
+
// so the in-context file paths these tests build must resolve against the
|
|
1990
|
+
// same per-test workspace the injector sees.
|
|
1991
|
+
const pkbRoot = getPkbRoot();
|
|
1992
|
+
|
|
1993
|
+
// The pkb-reminder injector reads the dense/sparse PKB query pair off the
|
|
1994
|
+
// conversation's live graph handle (the memory-retrieval hook records it
|
|
1995
|
+
// there during retrieval), not from the injection options. Register a handle
|
|
1996
|
+
// for the fallback conversation id `applyRuntimeInjections` synthesizes and
|
|
1997
|
+
// seed it with a query vector so the hint-search branch runs.
|
|
1998
|
+
let graphHandle: ConversationGraphMemory;
|
|
1999
|
+
beforeEach(() => {
|
|
2000
|
+
graphHandle = new ConversationGraphMemory("runtime-assembly-fallback");
|
|
2001
|
+
graphHandle.recordPkbQueryVectors([0.1, 0.2, 0.3], undefined);
|
|
2002
|
+
});
|
|
2003
|
+
afterEach(() => {
|
|
2004
|
+
graphHandle.dispose();
|
|
2005
|
+
});
|
|
2006
|
+
|
|
2007
|
+
// PKB content makes `readPkbContext()` non-null so the (vellum/guardian-
|
|
2008
|
+
// equivalent) fallback trust gate admits the reminder; cleared after each
|
|
2009
|
+
// test to avoid leaking into suites that assert the reminder is absent.
|
|
2010
|
+
beforeEach(seedPkbContent);
|
|
2011
|
+
afterEach(clearPkbContent);
|
|
2040
2012
|
|
|
2041
2013
|
function makePkbOptions(overrides: Record<string, unknown> = {}) {
|
|
2042
2014
|
return {
|
|
2043
|
-
pkbActive: true,
|
|
2044
|
-
pkbQueryVector: [0.1, 0.2, 0.3],
|
|
2045
|
-
pkbScopeId: "scope-1",
|
|
2046
|
-
pkbConversation: { messages: baseMessages },
|
|
2047
|
-
pkbRoot,
|
|
2048
|
-
pkbWorkingDir,
|
|
2049
|
-
pkbAutoInjectList: [],
|
|
2050
2015
|
...overrides,
|
|
2051
2016
|
};
|
|
2052
2017
|
}
|
|
@@ -2082,10 +2047,11 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2082
2047
|
test("default auto-injected files (from PKB_DEFAULT_FILES) are filtered out of hints", async () => {
|
|
2083
2048
|
// Regression test: when `_autoinject.md` is missing, `readPkbContext`
|
|
2084
2049
|
// falls back to PKB_DEFAULT_FILES — so those files ARE in the prompt.
|
|
2085
|
-
// The
|
|
2086
|
-
//
|
|
2087
|
-
//
|
|
2088
|
-
//
|
|
2050
|
+
// The injector sources the same fallback via `getPkbAutoInjectList`, so
|
|
2051
|
+
// it must know about them too, otherwise the reminder would redundantly
|
|
2052
|
+
// recommend e.g. `essentials.md` even though its contents are already
|
|
2053
|
+
// injected. The per-test workspace has no `_autoinject.md`, so the
|
|
2054
|
+
// injector resolves PKB_DEFAULT_FILES here.
|
|
2089
2055
|
pkbSearchResults = [
|
|
2090
2056
|
{ path: "essentials.md", denseScore: 0.95 },
|
|
2091
2057
|
{ path: "topics/alpha.md", denseScore: 0.9 },
|
|
@@ -2094,16 +2060,7 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2094
2060
|
|
|
2095
2061
|
const { messages: result } = await applyRuntimeInjections(
|
|
2096
2062
|
baseMessages,
|
|
2097
|
-
makePkbOptions(
|
|
2098
|
-
// Simulate the fallback the agent-loop now threads through:
|
|
2099
|
-
// `_autoinject.md` is missing, so defaults are injected.
|
|
2100
|
-
pkbAutoInjectList: [
|
|
2101
|
-
"INDEX.md",
|
|
2102
|
-
"essentials.md",
|
|
2103
|
-
"threads.md",
|
|
2104
|
-
"buffer.md",
|
|
2105
|
-
],
|
|
2106
|
-
}),
|
|
2063
|
+
makePkbOptions(),
|
|
2107
2064
|
);
|
|
2108
2065
|
const texts = extractTexts(result);
|
|
2109
2066
|
const reminder = texts.find((t) => t.startsWith("<system_reminder>"));
|
|
@@ -2143,27 +2100,26 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2143
2100
|
];
|
|
2144
2101
|
pkbSearchThrows = null;
|
|
2145
2102
|
|
|
2146
|
-
//
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
};
|
|
2103
|
+
// Working messages where topics/beta.md was already read via file_read on
|
|
2104
|
+
// an earlier turn, followed by the current user prompt as the tail.
|
|
2105
|
+
const conversationWithRead: Message[] = [
|
|
2106
|
+
{
|
|
2107
|
+
role: "assistant",
|
|
2108
|
+
content: [
|
|
2109
|
+
{
|
|
2110
|
+
type: "tool_use",
|
|
2111
|
+
id: "tu_1",
|
|
2112
|
+
name: "file_read",
|
|
2113
|
+
input: { path: `${pkbRoot}/topics/beta.md` },
|
|
2114
|
+
},
|
|
2115
|
+
],
|
|
2116
|
+
},
|
|
2117
|
+
...baseMessages,
|
|
2118
|
+
];
|
|
2163
2119
|
|
|
2164
2120
|
const { messages: result } = await applyRuntimeInjections(
|
|
2165
|
-
|
|
2166
|
-
makePkbOptions(
|
|
2121
|
+
conversationWithRead,
|
|
2122
|
+
makePkbOptions(),
|
|
2167
2123
|
);
|
|
2168
2124
|
const texts = extractTexts(result);
|
|
2169
2125
|
const reminder = texts.find((t) => t.startsWith("<system_reminder>"));
|
|
@@ -2201,10 +2157,13 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2201
2157
|
|
|
2202
2158
|
test("missing query vector → flat fallback, search is not attempted", async () => {
|
|
2203
2159
|
pkbSearchThrows = new Error("should not be called");
|
|
2160
|
+
// No dense vector was recorded on the graph handle this turn, so the
|
|
2161
|
+
// injector must skip the hint search entirely.
|
|
2162
|
+
graphHandle.recordPkbQueryVectors(undefined, undefined);
|
|
2204
2163
|
|
|
2205
2164
|
const { messages: result } = await applyRuntimeInjections(
|
|
2206
2165
|
baseMessages,
|
|
2207
|
-
makePkbOptions(
|
|
2166
|
+
makePkbOptions(),
|
|
2208
2167
|
);
|
|
2209
2168
|
const texts = extractTexts(result);
|
|
2210
2169
|
const reminder = texts.find((t) => t.startsWith("<system_reminder>"));
|
|
@@ -2318,37 +2277,28 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2318
2277
|
];
|
|
2319
2278
|
pkbSearchThrows = null;
|
|
2320
2279
|
|
|
2321
|
-
// Pre-compaction
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
};
|
|
2280
|
+
// Pre-compaction working messages: beta was already read on an earlier
|
|
2281
|
+
// turn, followed by the current user prompt as the tail.
|
|
2282
|
+
const preCompactionMessages: Message[] = [
|
|
2283
|
+
{
|
|
2284
|
+
role: "assistant",
|
|
2285
|
+
content: [
|
|
2286
|
+
{
|
|
2287
|
+
type: "tool_use",
|
|
2288
|
+
id: "tu_pre",
|
|
2289
|
+
name: "file_read",
|
|
2290
|
+
input: { path: `${pkbRoot}/topics/beta.md` },
|
|
2291
|
+
},
|
|
2292
|
+
],
|
|
2293
|
+
},
|
|
2294
|
+
...baseMessages,
|
|
2295
|
+
];
|
|
2338
2296
|
|
|
2339
2297
|
// 1. Initial injection sees the pre-compaction state — beta should be
|
|
2340
2298
|
// filtered out.
|
|
2341
2299
|
const { messages: initialResult } = await applyRuntimeInjections(
|
|
2342
|
-
|
|
2343
|
-
{
|
|
2344
|
-
pkbActive: true,
|
|
2345
|
-
pkbQueryVector: [0.1, 0.2],
|
|
2346
|
-
pkbScopeId: "scope-1",
|
|
2347
|
-
pkbConversation: preCompactionConversation,
|
|
2348
|
-
pkbRoot,
|
|
2349
|
-
pkbWorkingDir,
|
|
2350
|
-
pkbAutoInjectList: [],
|
|
2351
|
-
},
|
|
2300
|
+
preCompactionMessages,
|
|
2301
|
+
{},
|
|
2352
2302
|
);
|
|
2353
2303
|
// Unwrap the injected reminder from the last user message.
|
|
2354
2304
|
const initialTexts = extractTexts(initialResult);
|
|
@@ -2360,41 +2310,29 @@ describe("applyRuntimeInjections — PKB relevance hints", () => {
|
|
|
2360
2310
|
expect(initialReminder).toBeDefined();
|
|
2361
2311
|
expect(initialReminder).not.toContain("- topics/beta.md");
|
|
2362
2312
|
|
|
2363
|
-
// 2.
|
|
2364
|
-
//
|
|
2365
|
-
//
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
},
|
|
2381
|
-
],
|
|
2382
|
-
};
|
|
2383
|
-
const postCompactionMessages = stripInjectionsForCompaction(initialResult);
|
|
2313
|
+
// 2. After compaction the working messages reflect the post-compaction
|
|
2314
|
+
// state: beta's tool_use was serialized into summary text and dropped,
|
|
2315
|
+
// so the only live file_read is the newly-read gamma.
|
|
2316
|
+
const postCompactionMessages: Message[] = [
|
|
2317
|
+
{
|
|
2318
|
+
role: "assistant",
|
|
2319
|
+
content: [
|
|
2320
|
+
{
|
|
2321
|
+
type: "tool_use",
|
|
2322
|
+
id: "tu_post",
|
|
2323
|
+
name: "file_read",
|
|
2324
|
+
input: { path: `${pkbRoot}/topics/gamma.md` },
|
|
2325
|
+
},
|
|
2326
|
+
],
|
|
2327
|
+
},
|
|
2328
|
+
...baseMessages,
|
|
2329
|
+
];
|
|
2384
2330
|
|
|
2385
|
-
// 3. Re-inject
|
|
2331
|
+
// 3. Re-inject over the post-compaction messages — gamma (now in context)
|
|
2386
2332
|
// should be filtered, and beta (no longer "in context") should appear.
|
|
2387
2333
|
const { messages: rebuiltResult } = await applyRuntimeInjections(
|
|
2388
2334
|
postCompactionMessages,
|
|
2389
|
-
{
|
|
2390
|
-
pkbActive: true,
|
|
2391
|
-
pkbQueryVector: [0.1, 0.2],
|
|
2392
|
-
pkbScopeId: "scope-1",
|
|
2393
|
-
pkbConversation: postCompactionConversation,
|
|
2394
|
-
pkbRoot,
|
|
2395
|
-
pkbWorkingDir,
|
|
2396
|
-
pkbAutoInjectList: [],
|
|
2397
|
-
},
|
|
2335
|
+
{},
|
|
2398
2336
|
);
|
|
2399
2337
|
const rebuiltTexts = extractTexts(rebuiltResult);
|
|
2400
2338
|
const rebuiltReminder = rebuiltTexts.find(
|
|
@@ -5100,11 +5038,15 @@ describe("applyRuntimeInjections blocks.pkbSystemReminder", () => {
|
|
|
5100
5038
|
},
|
|
5101
5039
|
];
|
|
5102
5040
|
|
|
5041
|
+
// The reminder gate hinges on PKB content presence; clear it after each test
|
|
5042
|
+
// so the "PKB inactive" case starts from an empty workspace pkb dir.
|
|
5043
|
+
afterEach(clearPkbContent);
|
|
5044
|
+
|
|
5103
5045
|
test("captures exact reminder bytes when full mode and PKB active", async () => {
|
|
5046
|
+
seedPkbContent();
|
|
5104
5047
|
pkbSearchResults = [];
|
|
5105
5048
|
pkbSearchThrows = null;
|
|
5106
5049
|
const { blocks } = await applyRuntimeInjections(baseMessages, {
|
|
5107
|
-
pkbActive: true,
|
|
5108
5050
|
mode: "full",
|
|
5109
5051
|
});
|
|
5110
5052
|
|
|
@@ -5113,8 +5055,8 @@ describe("applyRuntimeInjections blocks.pkbSystemReminder", () => {
|
|
|
5113
5055
|
});
|
|
5114
5056
|
|
|
5115
5057
|
test("not captured in minimal mode", async () => {
|
|
5058
|
+
seedPkbContent();
|
|
5116
5059
|
const { blocks } = await applyRuntimeInjections(baseMessages, {
|
|
5117
|
-
pkbActive: true,
|
|
5118
5060
|
mode: "minimal",
|
|
5119
5061
|
});
|
|
5120
5062
|
|
|
@@ -5123,7 +5065,6 @@ describe("applyRuntimeInjections blocks.pkbSystemReminder", () => {
|
|
|
5123
5065
|
|
|
5124
5066
|
test("not captured when PKB inactive", async () => {
|
|
5125
5067
|
const { blocks } = await applyRuntimeInjections(baseMessages, {
|
|
5126
|
-
pkbActive: false,
|
|
5127
5068
|
mode: "full",
|
|
5128
5069
|
});
|
|
5129
5070
|
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { applyRuntimeInjections } from "../daemon/conversation-runtime-assembly.js";
|
|
4
|
-
import { defaultInjectorsPlugin } from "../plugins/defaults/injectors/register.js";
|
|
5
|
-
import {
|
|
6
|
-
registerPlugin,
|
|
7
|
-
resetPluginRegistryForTests,
|
|
8
|
-
} from "../plugins/registry.js";
|
|
9
4
|
import type { Message } from "../providers/types.js";
|
|
10
5
|
|
|
11
6
|
// ---------------------------------------------------------------------------
|
|
@@ -23,21 +18,11 @@ function userMsg(text: string): Message {
|
|
|
23
18
|
const sampleContext =
|
|
24
19
|
"<workspace>\nRoot: /sandbox\nDirectories: src, lib, tests\n</workspace>";
|
|
25
20
|
|
|
26
|
-
// The
|
|
27
|
-
// G2.1. The workspace-context default injector (registered by
|
|
28
|
-
// `defaultInjectorsPlugin`) now emits the workspace block as a
|
|
21
|
+
// The workspace-context default injector emits the workspace block as a
|
|
29
22
|
// `prepend-user-tail` placement during `applyRuntimeInjections`. The suite
|
|
30
|
-
// below exercises that end-to-end path
|
|
23
|
+
// below exercises that end-to-end path.
|
|
31
24
|
|
|
32
25
|
describe("applyRuntimeInjections — workspace top-level context", () => {
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
// Post-G2.1: workspace injection is driven by the `workspace-context`
|
|
35
|
-
// default injector, so the plugin must be registered for the chain to
|
|
36
|
-
// produce a block. Each test gets a clean registry.
|
|
37
|
-
resetPluginRegistryForTests();
|
|
38
|
-
registerPlugin(defaultInjectorsPlugin);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
26
|
test("injects workspace context when provided", async () => {
|
|
42
27
|
const messages: Message[] = [userMsg("Hello")];
|
|
43
28
|
const { messages: result } = await applyRuntimeInjections(messages, {
|
|
@@ -86,7 +71,6 @@ describe("applyRuntimeInjections — workspace top-level context", () => {
|
|
|
86
71
|
html: "<div>test</div>",
|
|
87
72
|
appId: "app-1",
|
|
88
73
|
appName: "Example App",
|
|
89
|
-
appFiles: [],
|
|
90
74
|
},
|
|
91
75
|
workspaceTopLevelContext: null,
|
|
92
76
|
});
|
|
@@ -98,11 +82,6 @@ describe("applyRuntimeInjections — workspace top-level context", () => {
|
|
|
98
82
|
});
|
|
99
83
|
|
|
100
84
|
describe("applyRuntimeInjections — minimal mode skips workspace blocks", () => {
|
|
101
|
-
beforeEach(() => {
|
|
102
|
-
resetPluginRegistryForTests();
|
|
103
|
-
registerPlugin(defaultInjectorsPlugin);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
85
|
test("minimal mode skips workspace top-level context", async () => {
|
|
107
86
|
const messages: Message[] = [userMsg("Hello")];
|
|
108
87
|
const { messages: result } = await applyRuntimeInjections(messages, {
|