@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/bun.lock +2 -2
- 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/examples/plugins/echo/README.md +61 -66
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- 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__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- 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__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- 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 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- 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 +30 -10
- 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 +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- 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-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -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__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- 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 +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- 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-hidden-metadata.test.ts +38 -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__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- 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__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.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 +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- 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 +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- 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/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- 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/heartbeat.ts +9 -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 +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- 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 +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- 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-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- 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/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -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/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- 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/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- 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-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -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/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- 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/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -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/acp.ts +4 -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 +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- 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 +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- 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 +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -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/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -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/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -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 +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- 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__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- 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/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- 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 +66 -34
- 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/playground/helpers.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/surface-conversation-resolver.ts +4 -3
- 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/work-items-routes.ts +2 -4
- 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/runtime/services/conversation-serializer.ts +1 -1
- 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/signals/cancel.ts +2 -4
- 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/subagent/manager.ts +17 -5
- 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/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- 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/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- 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/051-seed-conversation-summarization-callsite.ts +4 -5
- 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 +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- 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__/pipeline-runner.test.ts +0 -564
- 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/memory/v3/provider-blocks.ts +0 -16
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- 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/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/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- 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
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -5,13 +5,21 @@
|
|
|
5
5
|
* before it is sent to the provider. They are pure (no side effects).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { join
|
|
8
|
+
import { statSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
10
|
|
|
11
11
|
import { type ChannelId, parseInterfaceId } from "../channels/types.js";
|
|
12
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
12
13
|
import { getConfig } from "../config/loader.js";
|
|
14
|
+
import { stripUserTextBlocksByPrefix } from "../context/strip-injections.js";
|
|
13
15
|
import { createContextSummaryMessage } from "../context/window-manager.js";
|
|
14
|
-
import {
|
|
16
|
+
import { getDocumentsForConversation } from "../documents/document-store.js";
|
|
17
|
+
import {
|
|
18
|
+
getApp,
|
|
19
|
+
getAppDirPath,
|
|
20
|
+
listAppFiles,
|
|
21
|
+
resolveAppDir,
|
|
22
|
+
} from "../memory/app-store.js";
|
|
15
23
|
import {
|
|
16
24
|
getMessages as defaultGetMessages,
|
|
17
25
|
type MessageRow,
|
|
@@ -21,8 +29,6 @@ import {
|
|
|
21
29
|
extractMemoryPrefixBlocks,
|
|
22
30
|
stripAllMemoryInjections,
|
|
23
31
|
} from "../memory/graph/conversation-graph-memory.js";
|
|
24
|
-
import type { QdrantSparseVector } from "../memory/qdrant-client.js";
|
|
25
|
-
import { MEMORY_V3_BLOCK_ID } from "../memory/v3/types.js";
|
|
26
32
|
import {
|
|
27
33
|
readSlackMetadata,
|
|
28
34
|
readSlackMetadataFromMessageMetadata,
|
|
@@ -35,9 +41,9 @@ import {
|
|
|
35
41
|
type RenderedSlackTranscriptMessage,
|
|
36
42
|
renderSlackTranscriptWithProvenance,
|
|
37
43
|
} from "../messaging/providers/slack/render-transcript.js";
|
|
38
|
-
import {
|
|
44
|
+
import { getInjectorChain } from "../plugins/defaults/memory-retrieval/injector-chain.js";
|
|
45
|
+
import { MEMORY_V3_BLOCK_ID } from "../plugins/defaults/memory-v3-shadow/types.js";
|
|
39
46
|
import type {
|
|
40
|
-
DiskPressureInjectionContext,
|
|
41
47
|
InjectionBlock,
|
|
42
48
|
InjectionPlacement,
|
|
43
49
|
TurnContext,
|
|
@@ -53,12 +59,19 @@ import { channelStatusToMemberStatus } from "../runtime/routes/inbound-stages/ac
|
|
|
53
59
|
import type { SubagentState } from "../subagent/types.js";
|
|
54
60
|
import { TERMINAL_STATUSES } from "../subagent/types.js";
|
|
55
61
|
import { canonicalizeInboundIdentity } from "../util/canonicalize-identity.js";
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
62
|
+
import { findConversationOrSubagent } from "./conversation-registry.js";
|
|
63
|
+
import type {
|
|
64
|
+
DynamicPageSurfaceData,
|
|
65
|
+
SurfaceData,
|
|
66
|
+
SurfaceType,
|
|
67
|
+
} from "./message-protocol.js";
|
|
58
68
|
import { filterMessagesForUntrustedActor } from "./message-provenance.js";
|
|
59
|
-
import { type PkbContextConversation } from "./pkb-context-tracker.js";
|
|
60
69
|
import type { TrustContext } from "./trust-context.js";
|
|
61
70
|
|
|
71
|
+
// The compaction strip lives in the compaction layer (`context/`) so the agent
|
|
72
|
+
// loop can own it; re-exported here for this module's existing consumers.
|
|
73
|
+
export { stripInjectionsForCompaction } from "../context/strip-injections.js";
|
|
74
|
+
|
|
62
75
|
/**
|
|
63
76
|
* Describes the capabilities of the channel through which the user is
|
|
64
77
|
* interacting. Used to gate UI-specific references and permission asks.
|
|
@@ -257,8 +270,8 @@ export function isGroupChatType(chatType?: string): boolean {
|
|
|
257
270
|
}
|
|
258
271
|
}
|
|
259
272
|
|
|
260
|
-
/** Context about the active workspace surface,
|
|
261
|
-
|
|
273
|
+
/** Context about the active workspace surface, rendered into the `<active_workspace>` block. */
|
|
274
|
+
interface ActiveSurfaceContext {
|
|
262
275
|
surfaceId: string;
|
|
263
276
|
html: string;
|
|
264
277
|
/** When set, the surface is backed by a persisted app. */
|
|
@@ -271,8 +284,72 @@ export interface ActiveSurfaceContext {
|
|
|
271
284
|
appPages?: Record<string, string>;
|
|
272
285
|
/** The page currently displayed in the WebView (e.g. "settings.html"). */
|
|
273
286
|
currentPage?: string;
|
|
274
|
-
|
|
275
|
-
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Resolve the conversation's active workspace surface into the context block
|
|
291
|
+
* consumed by {@link applyRuntimeInjections}, or `null` when no dynamic-page
|
|
292
|
+
* surface is active. App-backed surfaces are enriched with their persisted app
|
|
293
|
+
* metadata; the file tree is listed on demand by the injector.
|
|
294
|
+
*/
|
|
295
|
+
export function buildActiveSurfaceContext(params: {
|
|
296
|
+
currentActiveSurfaceId: string | undefined;
|
|
297
|
+
currentPage: string | undefined;
|
|
298
|
+
surfaceState: ReadonlyMap<
|
|
299
|
+
string,
|
|
300
|
+
{ surfaceType: SurfaceType; data: SurfaceData }
|
|
301
|
+
>;
|
|
302
|
+
}): ActiveSurfaceContext | null {
|
|
303
|
+
const { currentActiveSurfaceId, currentPage, surfaceState } = params;
|
|
304
|
+
if (!currentActiveSurfaceId) return null;
|
|
305
|
+
|
|
306
|
+
const stored = surfaceState.get(currentActiveSurfaceId);
|
|
307
|
+
if (!stored || stored.surfaceType !== "dynamic_page") return null;
|
|
308
|
+
|
|
309
|
+
const data = stored.data as DynamicPageSurfaceData;
|
|
310
|
+
const activeSurface: ActiveSurfaceContext = {
|
|
311
|
+
surfaceId: currentActiveSurfaceId,
|
|
312
|
+
html: data.html,
|
|
313
|
+
currentPage,
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
if (data.appId) {
|
|
317
|
+
const app = getApp(data.appId);
|
|
318
|
+
if (app) {
|
|
319
|
+
activeSurface.appId = app.id;
|
|
320
|
+
activeSurface.appName = app.name;
|
|
321
|
+
activeSurface.appDirName = resolveAppDir(app.id).dirName;
|
|
322
|
+
activeSurface.appSchemaJson = app.schemaJson;
|
|
323
|
+
if (app.pages && Object.keys(app.pages).length > 0) {
|
|
324
|
+
activeSurface.appPages = app.pages;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return activeSurface;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Lists the conversation's active documents as the lightweight summaries the
|
|
334
|
+
* `active-documents` injector surfaces to the assistant — letting it target
|
|
335
|
+
* existing documents with `document_update` instead of issuing duplicate
|
|
336
|
+
* `document_create` calls. Returns `null` when the conversation has none.
|
|
337
|
+
*/
|
|
338
|
+
export function buildActiveDocuments(conversationId: string): Array<{
|
|
339
|
+
surfaceId: string;
|
|
340
|
+
title: string;
|
|
341
|
+
wordCount: number;
|
|
342
|
+
updatedAt: number;
|
|
343
|
+
}> | null {
|
|
344
|
+
const conversationDocs = getDocumentsForConversation(conversationId);
|
|
345
|
+
return conversationDocs.length > 0
|
|
346
|
+
? conversationDocs.map((d) => ({
|
|
347
|
+
surfaceId: d.surfaceId,
|
|
348
|
+
title: d.title,
|
|
349
|
+
wordCount: d.wordCount,
|
|
350
|
+
updatedAt: d.updatedAt,
|
|
351
|
+
}))
|
|
352
|
+
: null;
|
|
276
353
|
}
|
|
277
354
|
|
|
278
355
|
const MAX_CONTEXT_LENGTH = 100_000;
|
|
@@ -315,7 +392,7 @@ function injectActiveSurfaceContext(
|
|
|
315
392
|
);
|
|
316
393
|
|
|
317
394
|
// File tree with sizes (capped at 50 files to bound prompt size)
|
|
318
|
-
const files =
|
|
395
|
+
const files = listAppFiles(ctx.appId);
|
|
319
396
|
const MAX_FILE_TREE_ENTRIES = 50;
|
|
320
397
|
const displayFiles = files.slice(0, MAX_FILE_TREE_ENTRIES);
|
|
321
398
|
lines.push("", "App files:");
|
|
@@ -490,7 +567,7 @@ export function buildSubagentStatusBlock(
|
|
|
490
567
|
}
|
|
491
568
|
|
|
492
569
|
// The `<active_subagents>` block is emitted by the `subagent-status` default
|
|
493
|
-
// injector (`plugins/defaults/injectors
|
|
570
|
+
// injector (`plugins/defaults/memory-retrieval/injectors.ts`) as an `append-user-tail`
|
|
494
571
|
// placement. Use {@link applyRuntimeInjections} with
|
|
495
572
|
// `options.subagentStatusBlock` set, or drive the injector chain directly
|
|
496
573
|
// via `collectInjectorBlocks`.
|
|
@@ -514,30 +591,7 @@ function injectVoiceCallControlContext(
|
|
|
514
591
|
// NOW.md scratchpad injection
|
|
515
592
|
// ---------------------------------------------------------------------------
|
|
516
593
|
|
|
517
|
-
/**
|
|
518
|
-
* Read the NOW.md scratchpad from the workspace prompt directory.
|
|
519
|
-
*
|
|
520
|
-
* Returns the trimmed content with `_`-prefixed comment lines stripped,
|
|
521
|
-
* or `null` if the file is missing, empty, or unreadable.
|
|
522
|
-
*/
|
|
523
|
-
export function readNowScratchpad(): string | null {
|
|
524
|
-
const nowPath = getWorkspacePromptPath("NOW.md");
|
|
525
|
-
if (!existsSync(nowPath)) return null;
|
|
526
|
-
try {
|
|
527
|
-
const stripped = stripCommentLines(readFileSync(nowPath, "utf-8")).trim();
|
|
528
|
-
return stripped.length > 0 ? stripped : null;
|
|
529
|
-
} catch {
|
|
530
|
-
return null;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
/**
|
|
535
|
-
* The `<NOW.md>` block is emitted by the `now-md` default injector
|
|
536
|
-
* (`plugins/defaults/injectors/register.ts`) as an `after-memory-prefix` placement.
|
|
537
|
-
* Use {@link applyRuntimeInjections} with `options.nowScratchpad` set.
|
|
538
|
-
*/
|
|
539
|
-
|
|
540
|
-
/** Strip `<NOW.md>` blocks injected by `injectNowScratchpad`. */
|
|
594
|
+
/** Strip `<NOW.md>` blocks injected by the `now-md` default injector. */
|
|
541
595
|
export function stripNowScratchpad(messages: Message[]): Message[] {
|
|
542
596
|
return stripUserTextBlocksByPrefix(messages, [
|
|
543
597
|
// Shared prefix catches both the current tag and any pre-line-limit
|
|
@@ -547,102 +601,6 @@ export function stripNowScratchpad(messages: Message[]): Message[] {
|
|
|
547
601
|
]);
|
|
548
602
|
}
|
|
549
603
|
|
|
550
|
-
// ---------------------------------------------------------------------------
|
|
551
|
-
// PKB (Personal Knowledge Base) injection
|
|
552
|
-
// ---------------------------------------------------------------------------
|
|
553
|
-
|
|
554
|
-
const PKB_DEFAULT_FILES = [
|
|
555
|
-
"INDEX.md",
|
|
556
|
-
"essentials.md",
|
|
557
|
-
"threads.md",
|
|
558
|
-
"buffer.md",
|
|
559
|
-
];
|
|
560
|
-
|
|
561
|
-
const AUTOINJECT_FILENAME = "_autoinject.md";
|
|
562
|
-
|
|
563
|
-
/** Max buffer.md lines injected into prompts — keeps context bounded even when filing is off. */
|
|
564
|
-
const MAX_BUFFER_LINES = 50;
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* Read `_autoinject.md` from the PKB directory and return the list of
|
|
568
|
-
* filenames to inject.
|
|
569
|
-
*
|
|
570
|
-
* - Returns `null` when the file is missing or unreadable — callers
|
|
571
|
-
* should fall back to the hardcoded defaults.
|
|
572
|
-
* - Returns `[]` when the file exists but has no entries (empty or
|
|
573
|
-
* comments only) — an explicit opt-out meaning "inject nothing."
|
|
574
|
-
*/
|
|
575
|
-
export function readAutoinjectList(pkbDir: string): string[] | null {
|
|
576
|
-
const filePath = join(pkbDir, AUTOINJECT_FILENAME);
|
|
577
|
-
if (!existsSync(filePath)) return null;
|
|
578
|
-
try {
|
|
579
|
-
const raw = stripCommentLines(readFileSync(filePath, "utf-8"));
|
|
580
|
-
const files = raw
|
|
581
|
-
.split("\n")
|
|
582
|
-
.map((l) => l.trim())
|
|
583
|
-
.filter((l) => l.length > 0);
|
|
584
|
-
return files.length > 0 ? files : [];
|
|
585
|
-
} catch {
|
|
586
|
-
return null;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* Resolve the effective list of auto-inject filenames for a PKB directory.
|
|
592
|
-
*
|
|
593
|
-
* This is the single source of truth used both by `readPkbContext` (which
|
|
594
|
-
* actually injects the files) and by the PKB reminder-hint tracker in
|
|
595
|
-
* `conversation-agent-loop.ts` (which needs to know what's already in
|
|
596
|
-
* context so it doesn't redundantly recommend those files).
|
|
597
|
-
*
|
|
598
|
-
* Returns `PKB_DEFAULT_FILES` when `_autoinject.md` is missing/unreadable,
|
|
599
|
-
* or the parsed list (possibly empty) when it is present.
|
|
600
|
-
*/
|
|
601
|
-
export function getPkbAutoInjectList(pkbRoot: string): string[] {
|
|
602
|
-
return readAutoinjectList(pkbRoot) ?? PKB_DEFAULT_FILES;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* Read the always-loaded PKB files and append a nudge encouraging the
|
|
607
|
-
* assistant to proactively read topic files and use `remember` aggressively.
|
|
608
|
-
*
|
|
609
|
-
* Which files are loaded is determined by `pkb/_autoinject.md` (one filename
|
|
610
|
-
* per line). Falls back to the built-in defaults when that file is absent.
|
|
611
|
-
*
|
|
612
|
-
* Returns the concatenated content ready for injection, or `null` if all
|
|
613
|
-
* files are missing or empty.
|
|
614
|
-
*/
|
|
615
|
-
export function readPkbContext(): string | null {
|
|
616
|
-
const pkbDir = join(getWorkspaceDir(), "pkb");
|
|
617
|
-
if (!existsSync(pkbDir)) return null;
|
|
618
|
-
|
|
619
|
-
const filesToInject = getPkbAutoInjectList(pkbDir);
|
|
620
|
-
|
|
621
|
-
const parts: string[] = [];
|
|
622
|
-
for (const file of filesToInject) {
|
|
623
|
-
// Path traversal guard: reject entries that escape the pkb directory
|
|
624
|
-
const filePath = resolve(pkbDir, file);
|
|
625
|
-
if (!filePath.startsWith(pkbDir + "/")) continue;
|
|
626
|
-
|
|
627
|
-
if (!existsSync(filePath)) continue;
|
|
628
|
-
try {
|
|
629
|
-
let content = stripCommentLines(readFileSync(filePath, "utf-8")).trim();
|
|
630
|
-
if (file === "buffer.md" && content.length > 0) {
|
|
631
|
-
// Cap buffer entries to prevent unbounded growth when filing is disabled
|
|
632
|
-
const lines = content.split("\n");
|
|
633
|
-
if (lines.length > MAX_BUFFER_LINES) {
|
|
634
|
-
content = lines.slice(-MAX_BUFFER_LINES).join("\n");
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
if (content.length > 0) parts.push(content);
|
|
638
|
-
} catch {
|
|
639
|
-
// Skip unreadable files
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
return parts.length > 0 ? parts.join("\n\n") : null;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
604
|
/**
|
|
647
605
|
* Prepend channel capability context to the last user message so the
|
|
648
606
|
* model knows what the current channel can and cannot do.
|
|
@@ -994,53 +952,6 @@ export function buildUnifiedTurnContextBlock(
|
|
|
994
952
|
return lines.join("\n");
|
|
995
953
|
}
|
|
996
954
|
|
|
997
|
-
// ---------------------------------------------------------------------------
|
|
998
|
-
// Prefix-based stripping primitive
|
|
999
|
-
// ---------------------------------------------------------------------------
|
|
1000
|
-
|
|
1001
|
-
/**
|
|
1002
|
-
* A matcher for an injected text block. A plain string matches by prefix
|
|
1003
|
-
* (`startsWith`). A `{ prefix, suffix }` wrapper requires BOTH the opening
|
|
1004
|
-
* prefix and the closing suffix, so user-authored content that merely begins
|
|
1005
|
-
* with an injection-like opening tag (e.g. a message discussing `<info>`
|
|
1006
|
-
* markup) is not mistaken for an injected block and dropped. This mirrors
|
|
1007
|
-
* `countMemoryPrefixBlocks`, which only treats `<memory>…</memory>` /
|
|
1008
|
-
* `<info>…</info>` blocks as injected when the full wrapper is present.
|
|
1009
|
-
*/
|
|
1010
|
-
type InjectionMatcher = string | { prefix: string; suffix: string };
|
|
1011
|
-
|
|
1012
|
-
/**
|
|
1013
|
-
* Remove text blocks from user messages that match any of the given matchers.
|
|
1014
|
-
* If stripping removes all content blocks from a message, the message itself
|
|
1015
|
-
* is dropped.
|
|
1016
|
-
*
|
|
1017
|
-
* This is the shared primitive behind the individual strip* functions and
|
|
1018
|
-
* the `stripInjectionsForCompaction` pipeline.
|
|
1019
|
-
*/
|
|
1020
|
-
function stripUserTextBlocksByPrefix(
|
|
1021
|
-
messages: Message[],
|
|
1022
|
-
matchers: InjectionMatcher[],
|
|
1023
|
-
): Message[] {
|
|
1024
|
-
return messages
|
|
1025
|
-
.map((message) => {
|
|
1026
|
-
if (message.role !== "user") return message;
|
|
1027
|
-
const nextContent = message.content.filter((block) => {
|
|
1028
|
-
if (block.type !== "text") return true;
|
|
1029
|
-
return !matchers.some((m) =>
|
|
1030
|
-
typeof m === "string"
|
|
1031
|
-
? block.text.startsWith(m)
|
|
1032
|
-
: block.text.startsWith(m.prefix) && block.text.endsWith(m.suffix),
|
|
1033
|
-
);
|
|
1034
|
-
});
|
|
1035
|
-
if (nextContent.length === message.content.length) return message;
|
|
1036
|
-
if (nextContent.length === 0) return null;
|
|
1037
|
-
return { ...message, content: nextContent };
|
|
1038
|
-
})
|
|
1039
|
-
.filter(
|
|
1040
|
-
(message): message is NonNullable<typeof message> => message != null,
|
|
1041
|
-
);
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
955
|
// ---------------------------------------------------------------------------
|
|
1045
956
|
// Individual strip functions (thin wrappers around the primitive)
|
|
1046
957
|
// ---------------------------------------------------------------------------
|
|
@@ -1726,98 +1637,6 @@ export function loadSlackActiveThreadFocusBlock(
|
|
|
1726
1637
|
return assembleSlackActiveThreadFocusBlock(rows, capabilities);
|
|
1727
1638
|
}
|
|
1728
1639
|
|
|
1729
|
-
/** Matchers stripped by the pipeline (order doesn't matter — single pass). */
|
|
1730
|
-
const RUNTIME_INJECTION_PREFIXES: InjectionMatcher[] = [
|
|
1731
|
-
"<channel_capabilities>",
|
|
1732
|
-
"<channel_command_context>",
|
|
1733
|
-
"<disk_pressure_warning>",
|
|
1734
|
-
"<channel_turn_context>", // backward-compat: strip legacy separate channel blocks
|
|
1735
|
-
"<guardian_context>",
|
|
1736
|
-
"<inbound_actor_context>", // backward-compat: strip legacy separate actor blocks
|
|
1737
|
-
"<interface_turn_context>", // backward-compat: strip legacy separate interface blocks
|
|
1738
|
-
// NOTE: <turn_context> is intentionally NOT stripped — unified turn context
|
|
1739
|
-
// blocks persist in history so the assistant retains temporal/actor grounding.
|
|
1740
|
-
"<background_turn>",
|
|
1741
|
-
"<memory_context __injected>",
|
|
1742
|
-
"<memory_context>", // backward-compat: strip legacy blocks from pre-__injected history
|
|
1743
|
-
// The static `memory-v2-static` block (`<info>\n…</info>`) and the
|
|
1744
|
-
// dynamic activation block (`<memory>\n…</memory>`, plus legacy
|
|
1745
|
-
// `<memory __injected>…`) are both stripped so each compaction
|
|
1746
|
-
// re-injects the freshest essentials/threads/recent/buffer view and
|
|
1747
|
-
// re-runs the activation pipeline, matching the `<knowledge_base>`
|
|
1748
|
-
// cadence. The activation pipeline dedupes via `everInjected`, and
|
|
1749
|
-
// compaction handles aggregate growth, so accumulation does not cause
|
|
1750
|
-
// unbounded context growth. Both wrappers may appear in persisted rows.
|
|
1751
|
-
//
|
|
1752
|
-
// These two use the full `{ prefix, suffix }` wrapper shape (not a bare
|
|
1753
|
-
// prefix) so that user-authored text merely starting with `<memory>\n` or
|
|
1754
|
-
// `<info>\n` is never silently dropped during compaction/`/clean`. This
|
|
1755
|
-
// matches the full-wrapper requirement in `countMemoryPrefixBlocks`.
|
|
1756
|
-
{ prefix: "<memory>\n", suffix: "\n</memory>" },
|
|
1757
|
-
{ prefix: "<info>\n", suffix: "\n</info>" },
|
|
1758
|
-
"<voice_call_control>",
|
|
1759
|
-
"<workspace_top_level>", // backward-compat: strip legacy workspace blocks
|
|
1760
|
-
// NOTE: <workspace> is intentionally NOT stripped — workspace context
|
|
1761
|
-
// persists in history so the assistant retains workspace grounding.
|
|
1762
|
-
"<temporal_context>\nToday:", // backward-compat: strip legacy temporal blocks
|
|
1763
|
-
"<active_subagents>",
|
|
1764
|
-
"<active_workspace>",
|
|
1765
|
-
"<active_dynamic_page>",
|
|
1766
|
-
"<non_interactive_context>",
|
|
1767
|
-
// Shared prefix catches both the current NOW.md tag and any pre-line-limit
|
|
1768
|
-
// variant that may linger in in-flight histories during a rolling deploy.
|
|
1769
|
-
"<NOW.md Always keep this up to date",
|
|
1770
|
-
"<now_scratchpad>", // backward-compat: strip legacy blocks from pre-rename history
|
|
1771
|
-
"<knowledge_base>",
|
|
1772
|
-
"<pkb>", // backward-compat: strip legacy tag from pre-rename history
|
|
1773
|
-
"<system_reminder>",
|
|
1774
|
-
"<transport_hints>",
|
|
1775
|
-
// The Slack active-thread focus block is non-persisted and injected on
|
|
1776
|
-
// the FINAL user turn only. Strip it here so re-assembly during compaction
|
|
1777
|
-
// and overflow recovery does not duplicate it across turns.
|
|
1778
|
-
"<active_thread>",
|
|
1779
|
-
"<system_notice>One or more tool calls returned an error.",
|
|
1780
|
-
];
|
|
1781
|
-
|
|
1782
|
-
/**
|
|
1783
|
-
* Strip all runtime-injected context from message history in a single pass.
|
|
1784
|
-
*
|
|
1785
|
-
* Used only during compaction and overflow recovery — not on normal turns.
|
|
1786
|
-
* Runtime injections persist in history to keep the conversation prefix
|
|
1787
|
-
* stable for Anthropic's prefix caching. Stripping is only needed when
|
|
1788
|
-
* compaction rewrites the message array (cache miss is expected anyway).
|
|
1789
|
-
*/
|
|
1790
|
-
export function stripInjectionsForCompaction(messages: Message[]): Message[] {
|
|
1791
|
-
return stripUserTextBlocksByPrefix(messages, RUNTIME_INJECTION_PREFIXES);
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
/**
|
|
1795
|
-
* Extract the most recently injected NOW.md content from the message history.
|
|
1796
|
-
* Returns null if no NOW.md injection is found.
|
|
1797
|
-
*/
|
|
1798
|
-
export function findLastInjectedNowContent(messages: Message[]): string | null {
|
|
1799
|
-
// Matches every NOW.md opening tag we emit (the tag text may evolve over
|
|
1800
|
-
// time, e.g. adding a line-limit hint), so in-flight histories with older
|
|
1801
|
-
// tag variants remain discoverable during a rolling deploy.
|
|
1802
|
-
const openTagPrefix = "<NOW.md Always keep this up to date";
|
|
1803
|
-
const suffix = "\n</NOW.md>";
|
|
1804
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1805
|
-
const msg = messages[i];
|
|
1806
|
-
if (msg.role !== "user") continue;
|
|
1807
|
-
for (const block of msg.content) {
|
|
1808
|
-
if (block.type !== "text" || !block.text.startsWith(openTagPrefix)) {
|
|
1809
|
-
continue;
|
|
1810
|
-
}
|
|
1811
|
-
const tagEnd = block.text.indexOf(">\n");
|
|
1812
|
-
if (tagEnd < 0) continue;
|
|
1813
|
-
const contentStart = tagEnd + ">\n".length;
|
|
1814
|
-
const end = block.text.lastIndexOf(suffix);
|
|
1815
|
-
if (end > contentStart) return block.text.slice(contentStart, end);
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
return null;
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
1640
|
/**
|
|
1822
1641
|
* Controls which runtime injections are applied.
|
|
1823
1642
|
*
|
|
@@ -1865,8 +1684,14 @@ export interface RuntimeInjectionResult {
|
|
|
1865
1684
|
}
|
|
1866
1685
|
|
|
1867
1686
|
/**
|
|
1868
|
-
* Run every
|
|
1869
|
-
* and return every non-null block
|
|
1687
|
+
* Run every {@link Injector} in the chain ({@link getInjectorChain}, already
|
|
1688
|
+
* sorted by ascending `order`) and return every non-null block it produced.
|
|
1689
|
+
*
|
|
1690
|
+
* `runMessages` is the turn's working message array, forwarded to each
|
|
1691
|
+
* injector so producers that need the current prompt contents read it from a
|
|
1692
|
+
* parameter rather than the shared {@link TurnContext}. Omitted by text-only
|
|
1693
|
+
* callers ({@link composeInjectorChain}) that drive the chain without a
|
|
1694
|
+
* message array.
|
|
1870
1695
|
*
|
|
1871
1696
|
* Injectors returning `null` are omitted from the result. The returned array
|
|
1872
1697
|
* preserves ascending-`order` sort so downstream callers (notably
|
|
@@ -1875,12 +1700,11 @@ export interface RuntimeInjectionResult {
|
|
|
1875
1700
|
*/
|
|
1876
1701
|
async function collectInjectorBlocks(
|
|
1877
1702
|
ctx: TurnContext,
|
|
1703
|
+
runMessages?: Message[],
|
|
1878
1704
|
): Promise<InjectionBlock[]> {
|
|
1879
|
-
const injectors = getInjectors();
|
|
1880
|
-
if (injectors.length === 0) return [];
|
|
1881
1705
|
const out: InjectionBlock[] = [];
|
|
1882
|
-
for (const injector of
|
|
1883
|
-
const block = await injector.produce(ctx);
|
|
1706
|
+
for (const injector of getInjectorChain()) {
|
|
1707
|
+
const block = await injector.produce(ctx, runMessages);
|
|
1884
1708
|
if (block) out.push(block);
|
|
1885
1709
|
}
|
|
1886
1710
|
return out;
|
|
@@ -1998,63 +1822,19 @@ function applyInjectionBlock(
|
|
|
1998
1822
|
* bag attached to the {@link TurnContext} the caller provides (or to an
|
|
1999
1823
|
* ephemeral {@link TurnContext} synthesized for test call sites). A small
|
|
2000
1824
|
* number of fields drive hardcoded branches that live outside the injector
|
|
2001
|
-
* chain — `
|
|
2002
|
-
*
|
|
2003
|
-
*
|
|
2004
|
-
*
|
|
1825
|
+
* chain — `isNonInteractive` — because it is orchestrator-owned content that
|
|
1826
|
+
* never made sense as a plugin-overridable default injector.
|
|
1827
|
+
*
|
|
1828
|
+
* The active workspace surface, the channel capabilities, the active document
|
|
1829
|
+
* list, the channel command context, the voice call-control prompt, and the
|
|
1830
|
+
* transport hints are not on this bag: `applyRuntimeInjections` resolves them
|
|
1831
|
+
* from the live conversation itself (its surface state, `channelCapabilities`,
|
|
1832
|
+
* the document store keyed by `conversationId`, its `commandIntent`, its
|
|
1833
|
+
* `voiceCallControlPrompt`, and its `transportHints` respectively), so the
|
|
1834
|
+
* orchestrator does not compute or thread them per turn.
|
|
2005
1835
|
*/
|
|
2006
1836
|
export interface RuntimeInjectionOptions {
|
|
2007
|
-
diskPressureContext?: DiskPressureInjectionContext | null;
|
|
2008
|
-
/**
|
|
2009
|
-
* Active dashboard-surface context (read from `<active_workspace>`). Kept
|
|
2010
|
-
* on the options bag rather than an injector because it is a
|
|
2011
|
-
* channel-capability concern that has never been gated as a default
|
|
2012
|
-
* injector.
|
|
2013
|
-
*/
|
|
2014
|
-
activeSurface?: ActiveSurfaceContext | null;
|
|
2015
|
-
workspaceTopLevelContext?: string | null;
|
|
2016
|
-
channelCapabilities?: ChannelCapabilities | null;
|
|
2017
|
-
channelCommandContext?: ChannelCommandContext | null;
|
|
2018
1837
|
unifiedTurnContext?: string | null;
|
|
2019
|
-
voiceCallControlPrompt?: string | null;
|
|
2020
|
-
pkbContext?: string | null;
|
|
2021
|
-
pkbActive?: boolean;
|
|
2022
|
-
/**
|
|
2023
|
-
* Dense query vector surfaced from the graph memory retriever.
|
|
2024
|
-
* When present together with `pkbActive`, used to run `searchPkbFiles`
|
|
2025
|
-
* to surface relevance hints in the PKB system reminder. When missing,
|
|
2026
|
-
* the reminder falls back to the flat static text.
|
|
2027
|
-
*/
|
|
2028
|
-
pkbQueryVector?: number[];
|
|
2029
|
-
/** Optional sparse vector accompanying `pkbQueryVector`. */
|
|
2030
|
-
pkbSparseVector?: QdrantSparseVector;
|
|
2031
|
-
/** Memory scope id used to filter PKB search results. */
|
|
2032
|
-
pkbScopeId?: string;
|
|
2033
|
-
/**
|
|
2034
|
-
* The live conversation (or a minimal shape containing `messages`) used
|
|
2035
|
-
* to compute which PKB paths are already "in context" and therefore
|
|
2036
|
-
* suppressed from hint suggestions.
|
|
2037
|
-
*/
|
|
2038
|
-
pkbConversation?: PkbContextConversation;
|
|
2039
|
-
/** Auto-injected PKB filenames (resolved relative to `pkbRoot`). */
|
|
2040
|
-
pkbAutoInjectList?: string[];
|
|
2041
|
-
/** Absolute path to the PKB directory (e.g. `<workspace>/pkb`). */
|
|
2042
|
-
pkbRoot?: string;
|
|
2043
|
-
/**
|
|
2044
|
-
* Working directory against which relative `file_read` tool paths
|
|
2045
|
-
* resolve, used to detect workspace-relative reads like
|
|
2046
|
-
* `pkb/threads.md`. Falls back to `pkbRoot` when omitted.
|
|
2047
|
-
*/
|
|
2048
|
-
pkbWorkingDir?: string;
|
|
2049
|
-
/**
|
|
2050
|
-
* Pre-rendered v2 static memory content (essentials/threads/recent/buffer
|
|
2051
|
-
* concatenated, header-wrapped). When non-null on full-mode turns the
|
|
2052
|
-
* `memory-v2-static` injector wraps it in `<info>` and splices it onto
|
|
2053
|
-
* the user message; subsequent turns leave the prior block cached on its
|
|
2054
|
-
* original user message.
|
|
2055
|
-
*/
|
|
2056
|
-
memoryV2Static?: string | null;
|
|
2057
|
-
nowScratchpad?: string | null;
|
|
2058
1838
|
subagentStatusBlock?: string | null;
|
|
2059
1839
|
isNonInteractive?: boolean;
|
|
2060
1840
|
/**
|
|
@@ -2064,7 +1844,6 @@ export interface RuntimeInjectionOptions {
|
|
|
2064
1844
|
* configured reminder.
|
|
2065
1845
|
*/
|
|
2066
1846
|
isBackgroundConversation?: boolean;
|
|
2067
|
-
transportHints?: string[] | null;
|
|
2068
1847
|
/**
|
|
2069
1848
|
* Pre-rendered Slack chronological transcript that replaces the
|
|
2070
1849
|
* default `runMessages` history for any Slack conversation (channels
|
|
@@ -2099,22 +1878,7 @@ export interface RuntimeInjectionOptions {
|
|
|
2099
1878
|
* `undefined` when the inbound is a top-level (non-thread) post.
|
|
2100
1879
|
*/
|
|
2101
1880
|
slackActiveThreadFocusBlock?: string | null;
|
|
2102
|
-
activeDocuments?: TurnInjectionInputs["activeDocuments"];
|
|
2103
1881
|
mode?: InjectionMode;
|
|
2104
|
-
/**
|
|
2105
|
-
* memory-v3-live: when true AND the v3 injector produced a `<memory>` block
|
|
2106
|
-
* this turn (placement `after-memory-prefix`, id `memory-v3`), the v2
|
|
2107
|
-
* `<memory>` injection that `graphMemory.prepareMemory` prepended to the
|
|
2108
|
-
* tail is stripped from EVERY user message before the v3 block is spliced —
|
|
2109
|
-
* so v3 becomes the sole `<memory>` source and history stays byte-stable for
|
|
2110
|
-
* prompt caching.
|
|
2111
|
-
*
|
|
2112
|
-
* The strip is keyed off whether v3 ACTUALLY produced a block, not off the
|
|
2113
|
-
* flag alone: when v3 errors or selects nothing (its injector returns
|
|
2114
|
-
* `null`), v2's block is left in place so the turn still ships memory rather
|
|
2115
|
-
* than dropping it (fallback-to-v2). Default false — v2 untouched.
|
|
2116
|
-
*/
|
|
2117
|
-
suppressV2MemoryForV3?: boolean;
|
|
2118
1882
|
/**
|
|
2119
1883
|
* Per-turn {@link TurnContext} forwarded to plugin-registered
|
|
2120
1884
|
* {@link Injector}s via {@link collectInjectorBlocks}. When omitted,
|
|
@@ -2141,44 +1905,35 @@ export interface RuntimeInjectionOptions {
|
|
|
2141
1905
|
*/
|
|
2142
1906
|
function buildTurnInjectionInputs(
|
|
2143
1907
|
options: RuntimeInjectionOptions,
|
|
1908
|
+
channelCapabilities: ChannelCapabilities | null,
|
|
1909
|
+
activeDocuments: TurnInjectionInputs["activeDocuments"],
|
|
2144
1910
|
): TurnInjectionInputs {
|
|
2145
1911
|
return {
|
|
2146
1912
|
mode: options.mode,
|
|
2147
|
-
diskPressureContext: options.diskPressureContext,
|
|
2148
|
-
workspaceTopLevelContext: options.workspaceTopLevelContext,
|
|
2149
1913
|
unifiedTurnContext: options.unifiedTurnContext,
|
|
2150
|
-
pkbContext: options.pkbContext,
|
|
2151
|
-
pkbActive: options.pkbActive,
|
|
2152
|
-
pkbQueryVector: options.pkbQueryVector,
|
|
2153
|
-
pkbSparseVector: options.pkbSparseVector,
|
|
2154
|
-
pkbScopeId: options.pkbScopeId,
|
|
2155
|
-
pkbConversation: options.pkbConversation,
|
|
2156
|
-
pkbAutoInjectList: options.pkbAutoInjectList,
|
|
2157
|
-
pkbRoot: options.pkbRoot,
|
|
2158
|
-
pkbWorkingDir: options.pkbWorkingDir,
|
|
2159
|
-
memoryV2Static: options.memoryV2Static,
|
|
2160
|
-
nowScratchpad: options.nowScratchpad,
|
|
2161
1914
|
subagentStatusBlock: options.subagentStatusBlock,
|
|
2162
|
-
channelCapabilities
|
|
1915
|
+
channelCapabilities,
|
|
2163
1916
|
slackChronologicalMessages: options.slackChronologicalMessages,
|
|
2164
1917
|
slackActiveThreadFocusBlock: options.slackActiveThreadFocusBlock,
|
|
2165
|
-
activeSurface: options.activeSurface,
|
|
2166
|
-
channelCommandContext: options.channelCommandContext,
|
|
2167
|
-
voiceCallControlPrompt: options.voiceCallControlPrompt,
|
|
2168
|
-
transportHints: options.transportHints,
|
|
2169
1918
|
isNonInteractive: options.isNonInteractive,
|
|
2170
1919
|
isBackgroundConversation: options.isBackgroundConversation,
|
|
2171
|
-
activeDocuments
|
|
1920
|
+
activeDocuments,
|
|
2172
1921
|
};
|
|
2173
1922
|
}
|
|
2174
1923
|
|
|
1924
|
+
/**
|
|
1925
|
+
* Conversation id used for the synthetic fallback {@link TurnContext} and the
|
|
1926
|
+
* live-conversation lookup when the caller omits a context (test call sites).
|
|
1927
|
+
*/
|
|
1928
|
+
const RUNTIME_ASSEMBLY_FALLBACK_CONVERSATION_ID = "runtime-assembly-fallback";
|
|
1929
|
+
|
|
2175
1930
|
/** Minimal synthetic TurnContext used when the caller omits one. */
|
|
2176
1931
|
function synthesizeFallbackTurnContext(
|
|
2177
1932
|
inputs: TurnInjectionInputs,
|
|
2178
1933
|
): TurnContext {
|
|
2179
1934
|
return {
|
|
2180
|
-
requestId:
|
|
2181
|
-
conversationId:
|
|
1935
|
+
requestId: RUNTIME_ASSEMBLY_FALLBACK_CONVERSATION_ID,
|
|
1936
|
+
conversationId: RUNTIME_ASSEMBLY_FALLBACK_CONVERSATION_ID,
|
|
2182
1937
|
turnIndex: 0,
|
|
2183
1938
|
trust: {
|
|
2184
1939
|
sourceChannel: inputs.channelCapabilities?.channel
|
|
@@ -2219,6 +1974,9 @@ function synthesizeFallbackTurnContext(
|
|
|
2219
1974
|
* 6. Run the remaining hardcoded branches (`isNonInteractive`,
|
|
2220
1975
|
* `voiceCallControlPrompt`, `activeSurface`, `channelCapabilities`,
|
|
2221
1976
|
* `channelCommandContext`, `transportHints`) in their historical order.
|
|
1977
|
+
* `voiceCallControlPrompt`, `activeSurface`, `channelCapabilities`,
|
|
1978
|
+
* `channelCommandContext`, and `transportHints` are sourced from the live
|
|
1979
|
+
* conversation rather than `options`.
|
|
2222
1980
|
* 7. Finally, apply the chain's remaining blocks by placement:
|
|
2223
1981
|
* `"append-user-tail"` in ascending `order`, then `"prepend-user-tail"`
|
|
2224
1982
|
* in descending `order` so the lowest-`order` prepend lands topmost in
|
|
@@ -2233,19 +1991,63 @@ export async function applyRuntimeInjections(
|
|
|
2233
1991
|
options: RuntimeInjectionOptions,
|
|
2234
1992
|
): Promise<RuntimeInjectionResult> {
|
|
2235
1993
|
const mode = options.mode ?? "full";
|
|
2236
|
-
|
|
1994
|
+
|
|
1995
|
+
// Source the channel capabilities from the live conversation rather than a
|
|
1996
|
+
// per-turn option computed by the orchestrator. The same value drives the
|
|
1997
|
+
// Slack-conversation gate, the `<channel_capabilities>` branch, and the
|
|
1998
|
+
// per-injector inputs the Slack injectors read.
|
|
1999
|
+
const conversationId =
|
|
2000
|
+
options.turnContext?.conversationId ??
|
|
2001
|
+
RUNTIME_ASSEMBLY_FALLBACK_CONVERSATION_ID;
|
|
2002
|
+
const channelCapabilities =
|
|
2003
|
+
findConversationOrSubagent(conversationId)?.channelCapabilities ?? null;
|
|
2004
|
+
const slackConversation = channelCapabilities?.channel === "slack";
|
|
2005
|
+
|
|
2006
|
+
// Source the active documents from the document store keyed by the same
|
|
2007
|
+
// conversation id rather than a per-turn option computed by the
|
|
2008
|
+
// orchestrator; the `active-documents` and `document-comments` injectors
|
|
2009
|
+
// read the result off their per-injector inputs.
|
|
2010
|
+
const activeDocuments = buildActiveDocuments(conversationId);
|
|
2011
|
+
|
|
2012
|
+
// Source the channel command intent (e.g. Telegram /start) from the live
|
|
2013
|
+
// conversation rather than a per-turn option. It is set on the conversation
|
|
2014
|
+
// at message-processing start and cleared at turn end, so the same value
|
|
2015
|
+
// drives the `<channel_command_context>` branch on every assembly call
|
|
2016
|
+
// within the turn.
|
|
2017
|
+
const channelCommandContext =
|
|
2018
|
+
findConversationOrSubagent(conversationId)?.commandIntent ?? null;
|
|
2019
|
+
|
|
2020
|
+
// Source the voice call-control prompt from the live conversation rather
|
|
2021
|
+
// than a per-turn option. The voice-session bridge sets it on the
|
|
2022
|
+
// conversation when a call attaches and clears it when the call ends, so
|
|
2023
|
+
// the same value drives the `<voice_call_control>` branch on every assembly
|
|
2024
|
+
// call within the turn.
|
|
2025
|
+
const voiceCallControlPrompt =
|
|
2026
|
+
findConversationOrSubagent(conversationId)?.voiceCallControlPrompt ?? null;
|
|
2027
|
+
|
|
2028
|
+
// Source the transport hints from the live conversation rather than a
|
|
2029
|
+
// per-turn option. They are set on the conversation from the inbound
|
|
2030
|
+
// message's transport when the message is processed, so the same value
|
|
2031
|
+
// drives the `<transport_hints>` branch on every assembly call within the
|
|
2032
|
+
// turn.
|
|
2033
|
+
const transportHints =
|
|
2034
|
+
findConversationOrSubagent(conversationId)?.transportHints ?? null;
|
|
2237
2035
|
|
|
2238
2036
|
// Build the per-injector inputs and attach them to the caller's
|
|
2239
2037
|
// TurnContext (without mutating it). When the caller didn't supply one,
|
|
2240
2038
|
// synthesize a minimal fallback so the chain still runs — test call sites
|
|
2241
2039
|
// that drive injection via `options` without constructing a full context
|
|
2242
2040
|
// continue to work.
|
|
2243
|
-
const injectionInputs = buildTurnInjectionInputs(
|
|
2041
|
+
const injectionInputs = buildTurnInjectionInputs(
|
|
2042
|
+
options,
|
|
2043
|
+
channelCapabilities,
|
|
2044
|
+
activeDocuments,
|
|
2045
|
+
);
|
|
2244
2046
|
const turnCtx: TurnContext = options.turnContext
|
|
2245
2047
|
? { ...options.turnContext, injectionInputs }
|
|
2246
2048
|
: synthesizeFallbackTurnContext(injectionInputs);
|
|
2247
2049
|
|
|
2248
|
-
const chainBlocks = await collectInjectorBlocks(turnCtx);
|
|
2050
|
+
const chainBlocks = await collectInjectorBlocks(turnCtx, runMessages);
|
|
2249
2051
|
|
|
2250
2052
|
// Split the chain output by placement so the downstream assembly can
|
|
2251
2053
|
// process each slot with the correct ordering rule.
|
|
@@ -2325,21 +2127,25 @@ export async function applyRuntimeInjections(
|
|
|
2325
2127
|
: undefined;
|
|
2326
2128
|
|
|
2327
2129
|
// ── Step 0: memory-v3-live v2 suppression ──
|
|
2328
|
-
// When v3
|
|
2329
|
-
// turn, v3 is the sole `<memory>` source. v2's `prepareMemory`
|
|
2330
|
-
// prepended its own `<memory>` block to the tail user message (and
|
|
2331
|
-
// turns may carry v2 blocks from earlier turns). Strip every user
|
|
2332
|
-
// memory prefix here so:
|
|
2130
|
+
// When the `memory-v3-live` flag is on AND the v3 injector actually produced
|
|
2131
|
+
// a block this turn, v3 is the sole `<memory>` source. v2's `prepareMemory`
|
|
2132
|
+
// already prepended its own `<memory>` block to the tail user message (and
|
|
2133
|
+
// historical turns may carry v2 blocks from earlier turns). Strip every user
|
|
2134
|
+
// message's memory prefix here so:
|
|
2333
2135
|
// 1. The v3 `after-memory-prefix` block (Step 2) lands at the top of the
|
|
2334
2136
|
// tail with no v2 prefix ahead of it — exactly one `<memory>` block.
|
|
2335
2137
|
// 2. History is byte-stable across turns for prompt caching.
|
|
2336
2138
|
// Keyed off the v3 block being present (not the flag alone) so a v3 failure
|
|
2337
2139
|
// (`produce()` → null) leaves v2's block intact — fallback rather than a
|
|
2338
2140
|
// memory-less turn. Idempotent: re-injection sites that already stripped
|
|
2339
|
-
// see no change.
|
|
2141
|
+
// see no change. Flag off → bit-for-bit identical to the v2 path.
|
|
2142
|
+
const suppressV2MemoryForV3 = isAssistantFeatureFlagEnabled(
|
|
2143
|
+
"memory-v3-live",
|
|
2144
|
+
getConfig(),
|
|
2145
|
+
);
|
|
2340
2146
|
const v3ProducedBlock = afterMemory.some((b) => b.id === MEMORY_V3_BLOCK_ID);
|
|
2341
2147
|
let runMessagesForAssembly = runMessages;
|
|
2342
|
-
if (
|
|
2148
|
+
if (suppressV2MemoryForV3 && v3ProducedBlock) {
|
|
2343
2149
|
runMessagesForAssembly = stripAllMemoryInjections(runMessages);
|
|
2344
2150
|
}
|
|
2345
2151
|
|
|
@@ -2410,42 +2216,56 @@ export async function applyRuntimeInjections(
|
|
|
2410
2216
|
}
|
|
2411
2217
|
}
|
|
2412
2218
|
|
|
2413
|
-
if (
|
|
2219
|
+
if (voiceCallControlPrompt) {
|
|
2414
2220
|
const userTail = result[result.length - 1];
|
|
2415
2221
|
if (userTail && userTail.role === "user") {
|
|
2416
2222
|
result = [
|
|
2417
2223
|
...result.slice(0, -1),
|
|
2418
|
-
injectVoiceCallControlContext(userTail,
|
|
2224
|
+
injectVoiceCallControlContext(userTail, voiceCallControlPrompt),
|
|
2419
2225
|
];
|
|
2420
2226
|
}
|
|
2421
2227
|
}
|
|
2422
2228
|
|
|
2423
|
-
if (mode === "full"
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2229
|
+
if (mode === "full") {
|
|
2230
|
+
// Source the active workspace surface from the live conversation's surface
|
|
2231
|
+
// state rather than from a per-turn option computed by the orchestrator.
|
|
2232
|
+
const surfaceConversation = findConversationOrSubagent(
|
|
2233
|
+
turnCtx.conversationId,
|
|
2234
|
+
);
|
|
2235
|
+
const activeSurface = surfaceConversation
|
|
2236
|
+
? buildActiveSurfaceContext({
|
|
2237
|
+
currentActiveSurfaceId: surfaceConversation.currentActiveSurfaceId,
|
|
2238
|
+
currentPage: surfaceConversation.currentPage,
|
|
2239
|
+
surfaceState: surfaceConversation.surfaceState,
|
|
2240
|
+
})
|
|
2241
|
+
: null;
|
|
2242
|
+
if (activeSurface) {
|
|
2243
|
+
const userTail = result[result.length - 1];
|
|
2244
|
+
if (userTail && userTail.role === "user") {
|
|
2245
|
+
result = [
|
|
2246
|
+
...result.slice(0, -1),
|
|
2247
|
+
injectActiveSurfaceContext(userTail, activeSurface),
|
|
2248
|
+
];
|
|
2249
|
+
}
|
|
2430
2250
|
}
|
|
2431
2251
|
}
|
|
2432
2252
|
|
|
2433
|
-
if (
|
|
2253
|
+
if (channelCapabilities) {
|
|
2434
2254
|
const userTail = result[result.length - 1];
|
|
2435
2255
|
if (userTail && userTail.role === "user") {
|
|
2436
2256
|
result = [
|
|
2437
2257
|
...result.slice(0, -1),
|
|
2438
|
-
injectChannelCapabilityContext(userTail,
|
|
2258
|
+
injectChannelCapabilityContext(userTail, channelCapabilities),
|
|
2439
2259
|
];
|
|
2440
2260
|
}
|
|
2441
2261
|
}
|
|
2442
2262
|
|
|
2443
|
-
if (mode === "full" &&
|
|
2263
|
+
if (mode === "full" && channelCommandContext) {
|
|
2444
2264
|
const userTail = result[result.length - 1];
|
|
2445
2265
|
if (userTail && userTail.role === "user") {
|
|
2446
2266
|
result = [
|
|
2447
2267
|
...result.slice(0, -1),
|
|
2448
|
-
injectChannelCommandContext(userTail,
|
|
2268
|
+
injectChannelCommandContext(userTail, channelCommandContext),
|
|
2449
2269
|
];
|
|
2450
2270
|
}
|
|
2451
2271
|
}
|
|
@@ -2459,14 +2279,14 @@ export async function applyRuntimeInjections(
|
|
|
2459
2279
|
if (
|
|
2460
2280
|
mode === "full" &&
|
|
2461
2281
|
!slackConversation &&
|
|
2462
|
-
|
|
2463
|
-
|
|
2282
|
+
transportHints &&
|
|
2283
|
+
transportHints.length > 0
|
|
2464
2284
|
) {
|
|
2465
2285
|
const userTail = result[result.length - 1];
|
|
2466
2286
|
if (userTail && userTail.role === "user") {
|
|
2467
2287
|
result = [
|
|
2468
2288
|
...result.slice(0, -1),
|
|
2469
|
-
injectTransportHints(userTail,
|
|
2289
|
+
injectTransportHints(userTail, transportHints),
|
|
2470
2290
|
];
|
|
2471
2291
|
}
|
|
2472
2292
|
}
|