@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
package/src/plugins/pipeline.ts
CHANGED
|
@@ -1,309 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Plugin
|
|
2
|
+
* Plugin hook runner.
|
|
3
3
|
*
|
|
4
|
-
* A "
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* covering success, error, and timeout uniformly.
|
|
4
|
+
* A "hook" is a named lifecycle event (`user-prompt-submit`, `post-tool-use`,
|
|
5
|
+
* …) that every registered plugin may handle. The runner walks each plugin's
|
|
6
|
+
* hook for a given event in registration order, threading a context value
|
|
7
|
+
* through the chain so hooks can observe and transform it.
|
|
9
8
|
*
|
|
10
|
-
* Design doc: `.private/plans/agent-plugin-system.md
|
|
11
|
-
*
|
|
12
|
-
* Semantics:
|
|
13
|
-
* - Onion composition — the first element of `middlewares` is the outermost
|
|
14
|
-
* wrapper; it sees the request first and the response last. Terminal runs
|
|
15
|
-
* in the middle.
|
|
16
|
-
* - Strict-fail — there is NO `try/catch` around user middleware. Errors,
|
|
17
|
-
* including `PluginTimeoutError` from a breached budget, propagate to the
|
|
18
|
-
* caller. The `finally` block only handles logging, never error recovery.
|
|
19
|
-
* - Timeout — when `timeoutMs` is a finite number, the invocation races a
|
|
20
|
-
* timer. A timeout rejection is a `PluginTimeoutError` carrying the
|
|
21
|
-
* pipeline name, the best-known offending plugin (from `ctx.pluginName`),
|
|
22
|
-
* and elapsed ms. When `timeoutMs` is `null`/`undefined`, no timer is
|
|
23
|
-
* armed — pipelines like `llmCall` and `toolExecute` rely on downstream
|
|
24
|
-
* timeouts instead.
|
|
9
|
+
* Design doc: `.private/plans/agent-plugin-system.md`.
|
|
25
10
|
*/
|
|
26
11
|
|
|
27
|
-
import type { Logger } from "pino";
|
|
28
|
-
|
|
29
12
|
import type { HookName } from "../plugin-api/constants.js";
|
|
30
|
-
import { getLogger } from "../util/logger.js";
|
|
31
13
|
import { getHooksFor } from "./registry.js";
|
|
32
|
-
import {
|
|
33
|
-
type Middleware,
|
|
34
|
-
type PipelineName,
|
|
35
|
-
PluginTimeoutError,
|
|
36
|
-
type TurnContext,
|
|
37
|
-
} from "./types.js";
|
|
38
|
-
|
|
39
|
-
const moduleLogger = getLogger("plugin-pipeline");
|
|
40
|
-
|
|
41
|
-
// ─── Default timeouts ───────────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Default per-pipeline timeout budgets in milliseconds. A value of `null`
|
|
45
|
-
* means the runner does NOT arm a timer — the pipeline relies on its
|
|
46
|
-
* downstream for budgeting (e.g. `llmCall` defers to provider-level HTTP
|
|
47
|
-
* timeouts; `toolExecute` defers to the per-tool timeout already enforced
|
|
48
|
-
* by `ToolExecutor`).
|
|
49
|
-
*
|
|
50
|
-
* Callers pass the appropriate entry as `runPipeline`'s `timeoutMs` argument.
|
|
51
|
-
* The design doc locks these numbers in; do not tweak without coordinating
|
|
52
|
-
* a design update.
|
|
53
|
-
*/
|
|
54
|
-
export const DEFAULT_TIMEOUTS: Record<PipelineName, number | null> = {
|
|
55
|
-
turn: null,
|
|
56
|
-
llmCall: null,
|
|
57
|
-
toolExecute: null,
|
|
58
|
-
memoryRetrieval: null,
|
|
59
|
-
tokenEstimate: null,
|
|
60
|
-
compaction: null,
|
|
61
|
-
overflowReduce: null,
|
|
62
|
-
persistence: null,
|
|
63
|
-
titleGenerate: null,
|
|
64
|
-
toolResultTruncate: null,
|
|
65
|
-
emptyResponse: null,
|
|
66
|
-
toolError: null,
|
|
67
|
-
circuitBreaker: null,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// ─── Composition ────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Compose an ordered list of {@link Middleware}s around a terminal handler
|
|
74
|
-
* using onion semantics. The first element of `middlewares` is the outermost
|
|
75
|
-
* layer.
|
|
76
|
-
*
|
|
77
|
-
* The returned function accepts `(args, ctx)` and runs the entire chain:
|
|
78
|
-
* ```
|
|
79
|
-
* middlewares[0] → middlewares[1] → ... → terminal → ... → middlewares[1] → middlewares[0]
|
|
80
|
-
* ```
|
|
81
|
-
*
|
|
82
|
-
* Middlewares that never call `next` short-circuit the chain — the terminal
|
|
83
|
-
* and any deeper middleware are never invoked. Middlewares that throw abort
|
|
84
|
-
* the chain; the error flows back out through any outer middleware unchanged
|
|
85
|
-
* (no internal try/catch).
|
|
86
|
-
*/
|
|
87
|
-
export function composeMiddleware<A, R>(
|
|
88
|
-
middlewares: ReadonlyArray<Middleware<A, R>>,
|
|
89
|
-
terminal: (args: A) => Promise<R>,
|
|
90
|
-
): (args: A, ctx: TurnContext) => Promise<R> {
|
|
91
|
-
return (args, ctx) => {
|
|
92
|
-
// Walk back-to-front, wrapping each middleware around `next`. The last
|
|
93
|
-
// middleware in the array wraps `terminal`; earlier entries wrap the
|
|
94
|
-
// accumulated chain so they execute first.
|
|
95
|
-
let next: (args: A) => Promise<R> = terminal;
|
|
96
|
-
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
97
|
-
const mw = middlewares[i]!;
|
|
98
|
-
const downstream = next;
|
|
99
|
-
next = (innerArgs: A) => mw(innerArgs, downstream, ctx);
|
|
100
|
-
}
|
|
101
|
-
return next(args);
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ─── Abort-signal linking ───────────────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Return a shallow-cloned `args` object where every `AbortSignal`-typed
|
|
109
|
-
* top-level property is swapped for a signal linked to `internalController`.
|
|
110
|
-
*
|
|
111
|
-
* "Linked" here means: the returned signal aborts when either the caller's
|
|
112
|
-
* original signal aborts OR `internalController` aborts (e.g. the pipeline
|
|
113
|
-
* timer fires). The caller's args are never mutated.
|
|
114
|
-
*
|
|
115
|
-
* When `args` carries no `AbortSignal` property, the original object is
|
|
116
|
-
* returned unchanged — pipelines whose terminals don't consume a signal
|
|
117
|
-
* (e.g. `persistence`, `tokenEstimate`) see identical behavior to before.
|
|
118
|
-
* The return value's `cleanup()` tears down any `addEventListener("abort",
|
|
119
|
-
* ...)` handlers attached to the caller's signal so a pipeline that
|
|
120
|
-
* completes successfully doesn't leak listeners on the caller's controller.
|
|
121
|
-
*/
|
|
122
|
-
function linkAbortSignal<A>(
|
|
123
|
-
args: A,
|
|
124
|
-
internalController: AbortController,
|
|
125
|
-
): { args: A; cleanup: () => void } {
|
|
126
|
-
if (args === null || typeof args !== "object") {
|
|
127
|
-
return { args, cleanup: () => {} };
|
|
128
|
-
}
|
|
129
|
-
const abortListeners: Array<{
|
|
130
|
-
signal: AbortSignal;
|
|
131
|
-
listener: () => void;
|
|
132
|
-
}> = [];
|
|
133
|
-
const record = args as Record<string, unknown>;
|
|
134
|
-
const patched: Record<string, unknown> = { ...record };
|
|
135
|
-
let swappedAny = false;
|
|
136
|
-
for (const key of Object.keys(record)) {
|
|
137
|
-
const value = record[key];
|
|
138
|
-
if (value instanceof AbortSignal) {
|
|
139
|
-
swappedAny = true;
|
|
140
|
-
if (value.aborted) {
|
|
141
|
-
// Caller already aborted — propagate immediately so the inner call
|
|
142
|
-
// sees the abort without waiting for the listener to fire.
|
|
143
|
-
internalController.abort();
|
|
144
|
-
} else {
|
|
145
|
-
const listener = () => internalController.abort();
|
|
146
|
-
value.addEventListener("abort", listener, { once: true });
|
|
147
|
-
abortListeners.push({ signal: value, listener });
|
|
148
|
-
}
|
|
149
|
-
patched[key] = internalController.signal;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
const cleanup = () => {
|
|
153
|
-
for (const { signal, listener } of abortListeners) {
|
|
154
|
-
signal.removeEventListener("abort", listener);
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
return { args: (swappedAny ? patched : args) as A, cleanup };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// ─── Runner ─────────────────────────────────────────────────────────────────
|
|
161
|
-
|
|
162
|
-
type PipelineLogRecord = {
|
|
163
|
-
event: "plugin.pipeline";
|
|
164
|
-
pipeline: PipelineName;
|
|
165
|
-
chain: ReadonlyArray<string>;
|
|
166
|
-
durationMs: number;
|
|
167
|
-
outcome: "success" | "error" | "timeout";
|
|
168
|
-
pluginName?: string;
|
|
169
|
-
errorName?: string;
|
|
170
|
-
errorMessage?: string;
|
|
171
|
-
errorStack?: string;
|
|
172
|
-
timeoutMs?: number;
|
|
173
|
-
requestId: string;
|
|
174
|
-
conversationId: string;
|
|
175
|
-
turnIndex?: number;
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Best-effort detection of a pino-compatible logger on the `TurnContext`.
|
|
180
|
-
*
|
|
181
|
-
* `TurnContext` intentionally doesn't require a logger slot — most code paths
|
|
182
|
-
* use the module-level logger. Some callers (notably plugin-scoped pipelines
|
|
183
|
-
* in later PRs) may attach a child logger via `(ctx as any).logger`. We type
|
|
184
|
-
* the field loosely to avoid coupling `TurnContext` to pino.
|
|
185
|
-
*/
|
|
186
|
-
function selectLogger(ctx: TurnContext): Logger {
|
|
187
|
-
const maybe = (ctx as { logger?: unknown }).logger;
|
|
188
|
-
if (maybe && typeof maybe === "object" && "info" in maybe) {
|
|
189
|
-
return maybe as Logger;
|
|
190
|
-
}
|
|
191
|
-
return moduleLogger;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Execute a named pipeline: compose middleware, run it under an optional
|
|
196
|
-
* timeout, and emit one structured log record covering success, error, or
|
|
197
|
-
* timeout uniformly.
|
|
198
|
-
*
|
|
199
|
-
* @param name The pipeline identifier. Used for telemetry and error
|
|
200
|
-
* attribution.
|
|
201
|
-
* @param middlewares Ordered list of middlewares to wrap around `terminal`.
|
|
202
|
-
* Names for the log `chain` are pulled from `Function.name`
|
|
203
|
-
* (empty strings are kept so length always matches).
|
|
204
|
-
* @param terminal The original behavior. Runs when all middlewares call
|
|
205
|
-
* `next`.
|
|
206
|
-
* @param args Pipeline-specific input payload.
|
|
207
|
-
* @param ctx Per-turn context. May carry an optional `logger` slot;
|
|
208
|
-
* otherwise the module logger is used.
|
|
209
|
-
* @param timeoutMs Deadline in milliseconds. `null`/`undefined` disables
|
|
210
|
-
* the timer entirely (inherits downstream timeouts).
|
|
211
|
-
*
|
|
212
|
-
* @throws {PluginTimeoutError} When `timeoutMs` is non-null and the chain
|
|
213
|
-
* exceeds the budget. `ctx.pluginName` (if set) is attached as the
|
|
214
|
-
* offending plugin.
|
|
215
|
-
* @throws Any error produced by user middleware or the terminal — flows
|
|
216
|
-
* through unchanged.
|
|
217
|
-
*/
|
|
218
|
-
export async function runPipeline<A, R>(
|
|
219
|
-
name: PipelineName,
|
|
220
|
-
middlewares: ReadonlyArray<Middleware<A, R>>,
|
|
221
|
-
terminal: (args: A) => Promise<R>,
|
|
222
|
-
args: A,
|
|
223
|
-
ctx: TurnContext,
|
|
224
|
-
timeoutMs?: number | null,
|
|
225
|
-
): Promise<R> {
|
|
226
|
-
const logger = selectLogger(ctx);
|
|
227
|
-
const chain = middlewares.map((m) => m.name || "anonymous");
|
|
228
|
-
const composed = composeMiddleware(middlewares, terminal);
|
|
229
|
-
const start = performance.now();
|
|
230
|
-
|
|
231
|
-
let outcome: "success" | "error" | "timeout" = "success";
|
|
232
|
-
let thrown: unknown = undefined;
|
|
233
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) {
|
|
237
|
-
const budget = timeoutMs;
|
|
238
|
-
// Internal controller: fires on either (a) the timer, so the inner call
|
|
239
|
-
// actually observes the budget breach instead of running forever after
|
|
240
|
-
// `Promise.race` rejects; or (b) the caller's own signal, so external
|
|
241
|
-
// cancellation still reaches the inner call transparently. Any
|
|
242
|
-
// `AbortSignal`-typed property on `args` (e.g. `signal` on
|
|
243
|
-
// `CompactionArgs`, `abortSignal` on `OverflowReduceArgs`) is swapped
|
|
244
|
-
// for this linked signal on a shallow-cloned args object — we never
|
|
245
|
-
// mutate the caller's args.
|
|
246
|
-
const internalController = new AbortController();
|
|
247
|
-
const { args: effectiveArgs, cleanup } = linkAbortSignal(
|
|
248
|
-
args,
|
|
249
|
-
internalController,
|
|
250
|
-
);
|
|
251
|
-
const timeoutPromise = new Promise<never>((_resolve, reject) => {
|
|
252
|
-
timer = setTimeout(() => {
|
|
253
|
-
internalController.abort();
|
|
254
|
-
reject(
|
|
255
|
-
new PluginTimeoutError(
|
|
256
|
-
name,
|
|
257
|
-
ctx.pluginName,
|
|
258
|
-
Math.round(performance.now() - start),
|
|
259
|
-
),
|
|
260
|
-
);
|
|
261
|
-
}, budget);
|
|
262
|
-
});
|
|
263
|
-
try {
|
|
264
|
-
return await Promise.race([
|
|
265
|
-
composed(effectiveArgs, ctx),
|
|
266
|
-
timeoutPromise,
|
|
267
|
-
]);
|
|
268
|
-
} finally {
|
|
269
|
-
cleanup();
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return await composed(args, ctx);
|
|
273
|
-
} catch (err) {
|
|
274
|
-
thrown = err;
|
|
275
|
-
outcome = err instanceof PluginTimeoutError ? "timeout" : "error";
|
|
276
|
-
throw err;
|
|
277
|
-
} finally {
|
|
278
|
-
if (timer !== undefined) clearTimeout(timer);
|
|
279
|
-
const durationMs = Math.round(performance.now() - start);
|
|
280
|
-
const record: PipelineLogRecord = {
|
|
281
|
-
event: "plugin.pipeline",
|
|
282
|
-
pipeline: name,
|
|
283
|
-
chain,
|
|
284
|
-
durationMs,
|
|
285
|
-
outcome,
|
|
286
|
-
requestId: ctx.requestId,
|
|
287
|
-
conversationId: ctx.conversationId,
|
|
288
|
-
};
|
|
289
|
-
if (ctx.turnIndex !== undefined) record.turnIndex = ctx.turnIndex;
|
|
290
|
-
if (ctx.pluginName !== undefined) record.pluginName = ctx.pluginName;
|
|
291
|
-
if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) {
|
|
292
|
-
record.timeoutMs = timeoutMs;
|
|
293
|
-
}
|
|
294
|
-
if (thrown !== undefined) {
|
|
295
|
-
if (thrown instanceof Error) {
|
|
296
|
-
record.errorName = thrown.name;
|
|
297
|
-
record.errorMessage = thrown.message;
|
|
298
|
-
if (thrown.stack) record.errorStack = thrown.stack;
|
|
299
|
-
} else {
|
|
300
|
-
record.errorName = "NonError";
|
|
301
|
-
record.errorMessage = String(thrown);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
logger.info(record, "plugin.pipeline");
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
14
|
|
|
308
15
|
// ─── Hook runner ────────────────────────────────────────────────────────────
|
|
309
16
|
|
|
@@ -314,12 +21,6 @@ export async function runPipeline<A, R>(
|
|
|
314
21
|
* that replaces the threaded value for subsequent hooks. The final context
|
|
315
22
|
* after the chain settles is returned.
|
|
316
23
|
*
|
|
317
|
-
* `runHook` is the hook-side counterpart to {@link runPipeline}:
|
|
318
|
-
* `runPipeline` composes middleware around a terminal handler for stateful
|
|
319
|
-
* request/response pipelines (memory retrieval, history repair, etc.);
|
|
320
|
-
* `runHook` walks ordered hook functions for declarative chain-style
|
|
321
|
-
* context transformations (`user-prompt-submit` today).
|
|
322
|
-
*
|
|
323
24
|
* @param name The hook identifier — pick one from {@link HOOKS}.
|
|
324
25
|
* @param initialCtx Context the first hook receives.
|
|
325
26
|
* @returns The final context after the chain settles. Same reference as
|
package/src/plugins/registry.ts
CHANGED
|
@@ -9,22 +9,17 @@
|
|
|
9
9
|
* closed-registration latch that protects `bootstrapPlugins()` from
|
|
10
10
|
* late-arriving registrations.
|
|
11
11
|
*
|
|
12
|
-
* Registration is order-preserving: {@link getRegisteredPlugins}
|
|
13
|
-
* {@link
|
|
14
|
-
*
|
|
15
|
-
* determines onion order for middleware composition in the pipeline runner.
|
|
12
|
+
* Registration is order-preserving: {@link getRegisteredPlugins} and
|
|
13
|
+
* {@link getHooksFor} reflect the order in which {@link registerPlugin} was
|
|
14
|
+
* called, which in turn determines the order plugin hooks run.
|
|
16
15
|
*
|
|
17
16
|
* This module does not call `Plugin.init()` — that is the job of the
|
|
18
|
-
* bootstrap
|
|
19
|
-
* later PRs introduce consumers.
|
|
17
|
+
* bootstrap. It also does not wire the registry into the daemon.
|
|
20
18
|
*
|
|
21
|
-
* Design doc: `.private/plans/agent-plugin-system.md
|
|
19
|
+
* Design doc: `.private/plans/agent-plugin-system.md`.
|
|
22
20
|
*/
|
|
23
21
|
|
|
24
22
|
import {
|
|
25
|
-
type Injector,
|
|
26
|
-
type PipelineMiddlewareMap,
|
|
27
|
-
type PipelineName,
|
|
28
23
|
type Plugin,
|
|
29
24
|
PluginExecutionError,
|
|
30
25
|
type PluginHookFn,
|
|
@@ -34,7 +29,7 @@ import {
|
|
|
34
29
|
|
|
35
30
|
/**
|
|
36
31
|
* Registered plugins keyed by `manifest.name`. A `Map` preserves insertion
|
|
37
|
-
* order, which the registry relies on for
|
|
32
|
+
* order, which the registry relies on for hook ordering and
|
|
38
33
|
* `getRegisteredPlugins()` output.
|
|
39
34
|
*/
|
|
40
35
|
const registeredPlugins = new Map<string, Plugin>();
|
|
@@ -47,8 +42,7 @@ const registeredPlugins = new Map<string, Plugin>();
|
|
|
47
42
|
* top-level `await` later resolves and still tries to call
|
|
48
43
|
* {@link registerPlugin}. Without the latch such a late arrival would land in
|
|
49
44
|
* the registry after `bootstrapPlugins()` has already walked it, leaving the
|
|
50
|
-
* plugin visible
|
|
51
|
-
* `init()` hook never invoked.
|
|
45
|
+
* plugin visible in the registry with its `init()` hook never invoked.
|
|
52
46
|
*/
|
|
53
47
|
let registrationClosed = false;
|
|
54
48
|
|
|
@@ -67,7 +61,7 @@ let registrationClosed = false;
|
|
|
67
61
|
*
|
|
68
62
|
* On success the plugin is appended to the registry in the order this
|
|
69
63
|
* function is called. This function does NOT invoke `plugin.init()` — that
|
|
70
|
-
* runs in the bootstrap sequence
|
|
64
|
+
* runs in the bootstrap sequence.
|
|
71
65
|
*/
|
|
72
66
|
export function registerPlugin(plugin: Plugin): void {
|
|
73
67
|
// Basic shape / required-field validation. The type system already enforces
|
|
@@ -144,27 +138,6 @@ export function getRegisteredPlugins(): Plugin[] {
|
|
|
144
138
|
return Array.from(registeredPlugins.values());
|
|
145
139
|
}
|
|
146
140
|
|
|
147
|
-
/**
|
|
148
|
-
* Collect the middleware each registered plugin contributes for the given
|
|
149
|
-
* pipeline, in registration order. Consumers feed the returned array into the
|
|
150
|
-
* pipeline runner's `composeMiddleware` helper (PR 12), which applies the
|
|
151
|
-
* outermost-first convention.
|
|
152
|
-
*
|
|
153
|
-
* Plugins that don't declare a middleware for `pipeline` are skipped.
|
|
154
|
-
*/
|
|
155
|
-
export function getMiddlewaresFor<P extends PipelineName>(
|
|
156
|
-
pipeline: P,
|
|
157
|
-
): PipelineMiddlewareMap[P][] {
|
|
158
|
-
const out: PipelineMiddlewareMap[P][] = [];
|
|
159
|
-
for (const plugin of registeredPlugins.values()) {
|
|
160
|
-
const middleware = plugin.middleware?.[pipeline];
|
|
161
|
-
if (middleware) {
|
|
162
|
-
out.push(middleware);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return out;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
141
|
/**
|
|
169
142
|
* Collect every registered plugin's hook for the given name, in
|
|
170
143
|
* registration order. Plugins that don't declare a hook for `name` are
|
|
@@ -190,22 +163,6 @@ export function getHooksFor<TCtx = unknown>(
|
|
|
190
163
|
return out;
|
|
191
164
|
}
|
|
192
165
|
|
|
193
|
-
/**
|
|
194
|
-
* Flatten every registered plugin's `injectors` array and sort the result by
|
|
195
|
-
* `order` ascending. Two injectors with the same `order` retain their relative
|
|
196
|
-
* registration order (stable sort via `Array.prototype.sort`).
|
|
197
|
-
*/
|
|
198
|
-
export function getInjectors(): Injector[] {
|
|
199
|
-
const out: Injector[] = [];
|
|
200
|
-
for (const plugin of registeredPlugins.values()) {
|
|
201
|
-
if (plugin.injectors && plugin.injectors.length > 0) {
|
|
202
|
-
out.push(...plugin.injectors);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
out.sort((a, b) => a.order - b.order);
|
|
206
|
-
return out;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
166
|
/**
|
|
210
167
|
* Close the per-boot registration window. After this call, any attempt to
|
|
211
168
|
* register a genuinely new plugin throws a {@link PluginExecutionError}.
|
|
@@ -225,10 +182,8 @@ export function closeRegistration(): void {
|
|
|
225
182
|
|
|
226
183
|
/**
|
|
227
184
|
* Remove a plugin from the registry. Invoked from the bootstrap's failure path
|
|
228
|
-
* after {@link Plugin.onShutdown} and contribution teardown have run, so
|
|
229
|
-
*
|
|
230
|
-
* plugin whose `init()` aborted mid-bootstrap. Without this, every subsequent
|
|
231
|
-
* pipeline invocation would re-enter the uninitialized plugin's middleware.
|
|
185
|
+
* after {@link Plugin.onShutdown} and contribution teardown have run, so the
|
|
186
|
+
* registry no longer exposes a plugin whose `init()` aborted mid-bootstrap.
|
|
232
187
|
* Safe to call on an already-absent name (no-op).
|
|
233
188
|
*/
|
|
234
189
|
export function unregisterPlugin(name: string): void {
|