@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +2 -2
- package/docs/plugins.md +832 -0
- package/examples/plugins/echo/README.md +60 -61
- package/examples/plugins/echo/package.json +2 -1
- package/examples/plugins/echo/register.ts +143 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
- package/openapi.yaml +5 -15
- package/package.json +2 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -4
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
- package/src/__tests__/conversation-agent-loop.test.ts +39 -42
- package/src/__tests__/conversation-clean-command.test.ts +2 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
- package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
- package/src/__tests__/conversation-starter-routes.test.ts +6 -14
- package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
- package/src/__tests__/db-acp-history.test.ts +0 -101
- package/src/__tests__/dynamic-page-surface.test.ts +0 -31
- package/src/__tests__/file-write-tool.test.ts +0 -63
- package/src/__tests__/gateway-only-guard.test.ts +2 -12
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- 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__/injector-background-turn.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +6 -34
- package/src/__tests__/injector-disk-pressure.test.ts +34 -77
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
- package/src/__tests__/pipeline-runner.test.ts +554 -0
- package/src/__tests__/plugin-api-shim.test.ts +6 -3
- package/src/__tests__/plugin-bootstrap.test.ts +23 -12
- package/src/__tests__/plugin-registry.test.ts +49 -3
- package/src/__tests__/plugin-types.test.ts +70 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +1 -4
- package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +3 -1
- package/src/__tests__/subagent-notify-parent.test.ts +3 -1
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +286 -54
- package/src/acp/__tests__/client-handler.test.ts +0 -40
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
- package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
- package/src/acp/agent-process.ts +1 -61
- package/src/acp/client-handler.ts +0 -31
- package/src/acp/prepare-agent-env.ts +29 -83
- package/src/acp/resolve-agent.test.ts +7 -320
- package/src/acp/resolve-agent.ts +18 -182
- package/src/acp/session-manager.ts +73 -495
- package/src/acp/types.ts +0 -8
- package/src/agent/compaction-circuit.ts +102 -60
- package/src/agent/loop.ts +59 -32
- package/src/api/responses/conversation-message.ts +1 -7
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +0 -1
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +31 -83
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
- package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +5 -14
- package/src/config/schemas/heartbeat.ts +0 -9
- package/src/context/strip-injections.ts +2 -8
- package/src/context/window-manager.ts +1 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
- package/src/daemon/conversation-agent-loop.ts +279 -62
- package/src/daemon/conversation-runtime-assembly.ts +69 -106
- package/src/daemon/conversation-store.ts +90 -9
- package/src/daemon/conversation-workspace.ts +0 -17
- package/src/daemon/conversation.ts +6 -0
- package/src/daemon/external-plugins-bootstrap.ts +11 -11
- package/src/daemon/handlers/conversations.ts +1 -3
- package/src/daemon/handlers/skills.ts +1 -4
- package/src/daemon/lifecycle.ts +0 -21
- package/src/daemon/server.ts +0 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
- package/src/heartbeat/heartbeat-run-store.ts +1 -23
- package/src/heartbeat/heartbeat-service.ts +0 -26
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -15
- package/src/ipc/skill-routes/memory.ts +2 -4
- package/src/memory/conversation-starter-checkpoints.ts +0 -1
- package/src/memory/db-init.ts +0 -2
- package/src/memory/job-handlers/conversation-starters.ts +2 -13
- package/src/memory/jobs-worker.ts +1 -1
- package/src/memory/migrations/index.ts +0 -1
- package/src/memory/schema/acp.ts +0 -4
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +4 -13
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
- package/src/plugin-api/index.ts +5 -0
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +19 -8
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/index.ts +5 -3
- package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +293 -6
- package/src/plugins/registry.ts +37 -9
- package/src/plugins/types.ts +336 -32
- package/src/plugins/user-loader.ts +127 -30
- package/src/proactive-artifact/aux-message-injector.ts +1 -1
- package/src/proactive-artifact/job.test.ts +1 -1
- package/src/prompts/__tests__/system-prompt.test.ts +0 -6
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
- package/src/runtime/__tests__/agent-wake.test.ts +5 -5
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +3 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +55 -283
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
- package/src/runtime/routes/acp-routes.test.ts +25 -89
- package/src/runtime/routes/acp-routes.ts +29 -81
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +10 -6
- 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 +1 -1
- package/src/runtime/routes/conversation-routes.ts +2 -15
- package/src/runtime/routes/conversation-starter-routes.ts +7 -13
- package/src/runtime/routes/conversations-import-routes.ts +7 -24
- 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-routes.ts +3 -18
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/memory-v3-routes.ts +6 -16
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
- package/src/runtime/routes/work-items-routes.ts +4 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +4 -2
- package/src/subagent/manager.ts +5 -17
- package/src/tools/acp/list-agents.test.ts +1 -7
- package/src/tools/acp/spawn.test.ts +55 -158
- package/src/tools/acp/spawn.ts +72 -47
- package/src/tools/acp/steer.test.ts +8 -105
- package/src/tools/acp/steer.ts +17 -48
- package/src/tools/apps/executors.ts +8 -13
- package/src/tools/filesystem/write.ts +0 -34
- package/src/tools/subagent/spawn.ts +4 -2
- package/src/tools/ui-surface/definitions.ts +4 -25
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
- package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
- package/examples/plugins/echo/hooks/stop.ts +0 -16
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
- package/examples/plugins/echo/src/emit.ts +0 -19
- package/src/__tests__/compaction-circuit.test.ts +0 -258
- package/src/__tests__/compaction-direct.test.ts +0 -132
- package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
- package/src/acp/__tests__/agent-process.test.ts +0 -161
- package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
- package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
- package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
- package/src/acp/auto-install.test.ts +0 -196
- package/src/acp/auto-install.ts +0 -177
- package/src/acp/feature-gate.test.ts +0 -48
- package/src/acp/feature-gate.ts +0 -34
- package/src/acp/resume-hint.ts +0 -25
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
- package/src/daemon/conversation-registry.ts +0 -159
- package/src/daemon/overflow-reduction-loop.ts +0 -230
- package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
- package/src/plugins/defaults/compaction/compact.ts +0 -59
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
- package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
- package/src/tools/acp/context.ts +0 -20
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
package/src/plugins/registry.ts
CHANGED
|
@@ -10,16 +10,20 @@
|
|
|
10
10
|
* late-arriving registrations.
|
|
11
11
|
*
|
|
12
12
|
* Registration is order-preserving: {@link getRegisteredPlugins} and
|
|
13
|
-
* {@link
|
|
14
|
-
* called, which in turn determines
|
|
13
|
+
* {@link getMiddlewaresFor} reflect the order in which {@link registerPlugin}
|
|
14
|
+
* was called, which in turn determines onion order for middleware composition
|
|
15
|
+
* in the pipeline runner.
|
|
15
16
|
*
|
|
16
17
|
* This module does not call `Plugin.init()` — that is the job of the
|
|
17
|
-
* bootstrap. It also does not wire the registry into the daemon
|
|
18
|
+
* bootstrap (see PR 14). It also does not wire the registry into the daemon;
|
|
19
|
+
* later PRs introduce consumers.
|
|
18
20
|
*
|
|
19
|
-
* Design doc: `.private/plans/agent-plugin-system.md
|
|
21
|
+
* Design doc: `.private/plans/agent-plugin-system.md` (PR 13).
|
|
20
22
|
*/
|
|
21
23
|
|
|
22
24
|
import {
|
|
25
|
+
type PipelineMiddlewareMap,
|
|
26
|
+
type PipelineName,
|
|
23
27
|
type Plugin,
|
|
24
28
|
PluginExecutionError,
|
|
25
29
|
type PluginHookFn,
|
|
@@ -29,7 +33,7 @@ import {
|
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
35
|
* Registered plugins keyed by `manifest.name`. A `Map` preserves insertion
|
|
32
|
-
* order, which the registry relies on for
|
|
36
|
+
* order, which the registry relies on for middleware composition and
|
|
33
37
|
* `getRegisteredPlugins()` output.
|
|
34
38
|
*/
|
|
35
39
|
const registeredPlugins = new Map<string, Plugin>();
|
|
@@ -42,7 +46,8 @@ const registeredPlugins = new Map<string, Plugin>();
|
|
|
42
46
|
* top-level `await` later resolves and still tries to call
|
|
43
47
|
* {@link registerPlugin}. Without the latch such a late arrival would land in
|
|
44
48
|
* the registry after `bootstrapPlugins()` has already walked it, leaving the
|
|
45
|
-
* plugin visible
|
|
49
|
+
* plugin visible to `getMiddlewaresFor()` with its
|
|
50
|
+
* `init()` hook never invoked.
|
|
46
51
|
*/
|
|
47
52
|
let registrationClosed = false;
|
|
48
53
|
|
|
@@ -61,7 +66,7 @@ let registrationClosed = false;
|
|
|
61
66
|
*
|
|
62
67
|
* On success the plugin is appended to the registry in the order this
|
|
63
68
|
* function is called. This function does NOT invoke `plugin.init()` — that
|
|
64
|
-
* runs in the bootstrap sequence.
|
|
69
|
+
* runs in the bootstrap sequence (PR 14).
|
|
65
70
|
*/
|
|
66
71
|
export function registerPlugin(plugin: Plugin): void {
|
|
67
72
|
// Basic shape / required-field validation. The type system already enforces
|
|
@@ -138,6 +143,27 @@ export function getRegisteredPlugins(): Plugin[] {
|
|
|
138
143
|
return Array.from(registeredPlugins.values());
|
|
139
144
|
}
|
|
140
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Collect the middleware each registered plugin contributes for the given
|
|
148
|
+
* pipeline, in registration order. Consumers feed the returned array into the
|
|
149
|
+
* pipeline runner's `composeMiddleware` helper (PR 12), which applies the
|
|
150
|
+
* outermost-first convention.
|
|
151
|
+
*
|
|
152
|
+
* Plugins that don't declare a middleware for `pipeline` are skipped.
|
|
153
|
+
*/
|
|
154
|
+
export function getMiddlewaresFor<P extends PipelineName>(
|
|
155
|
+
pipeline: P,
|
|
156
|
+
): PipelineMiddlewareMap[P][] {
|
|
157
|
+
const out: PipelineMiddlewareMap[P][] = [];
|
|
158
|
+
for (const plugin of registeredPlugins.values()) {
|
|
159
|
+
const middleware = plugin.middleware?.[pipeline];
|
|
160
|
+
if (middleware) {
|
|
161
|
+
out.push(middleware);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
141
167
|
/**
|
|
142
168
|
* Collect every registered plugin's hook for the given name, in
|
|
143
169
|
* registration order. Plugins that don't declare a hook for `name` are
|
|
@@ -182,8 +208,10 @@ export function closeRegistration(): void {
|
|
|
182
208
|
|
|
183
209
|
/**
|
|
184
210
|
* Remove a plugin from the registry. Invoked from the bootstrap's failure path
|
|
185
|
-
* after {@link Plugin.onShutdown} and contribution teardown have run, so
|
|
186
|
-
*
|
|
211
|
+
* after {@link Plugin.onShutdown} and contribution teardown have run, so
|
|
212
|
+
* {@link getMiddlewaresFor} no longer exposes a plugin whose `init()` aborted
|
|
213
|
+
* mid-bootstrap. Without this, every subsequent pipeline invocation would
|
|
214
|
+
* re-enter the uninitialized plugin's middleware.
|
|
187
215
|
* Safe to call on an already-absent name (no-op).
|
|
188
216
|
*/
|
|
189
217
|
export function unregisterPlugin(name: string): void {
|
package/src/plugins/types.ts
CHANGED
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin core types.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This file is scaffolding only — it defines the shape of the plugin system
|
|
5
|
+
* without wiring any behavior. Later PRs in the `agent-plugin-system` plan
|
|
6
|
+
* refine per-pipeline argument/result types (currently `unknown`-based
|
|
7
|
+
* placeholders) and add the pipeline runner, registry, and bootstrap.
|
|
8
|
+
*
|
|
9
|
+
* The assistant composes behavior around a small set of named pipelines
|
|
10
|
+
* (`compaction`, `overflowReduce`, ...). Each plugin may contribute one
|
|
11
|
+
* {@link Middleware} per pipeline; the registry composes them in onion
|
|
12
|
+
* order at runtime. Plugins may also contribute {@link Injector}s that emit
|
|
13
|
+
* system-prompt-time content, as well as model-visible capabilities
|
|
14
|
+
* (`tools`, `routes`, `skills`).
|
|
8
15
|
*
|
|
9
16
|
* Design doc: `.private/plans/agent-plugin-system.md`.
|
|
10
17
|
*/
|
|
11
18
|
|
|
12
19
|
import type { CompactionCircuitClosedEvent } from "../api/events/compaction-circuit-closed.js";
|
|
13
20
|
import type { CompactionCircuitOpenEvent } from "../api/events/compaction-circuit-open.js";
|
|
21
|
+
import type { ContextWindowConfig } from "../config/schemas/inference.js";
|
|
14
22
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
15
|
-
import type { ContextWindowManager } from "../context/window-manager.js";
|
|
16
23
|
import type {
|
|
24
|
+
ContextWindowManager,
|
|
25
|
+
ContextWindowResult,
|
|
26
|
+
} from "../context/window-manager.js";
|
|
27
|
+
import type { ReducerState } from "../daemon/context-overflow-reducer.js";
|
|
28
|
+
import type {
|
|
29
|
+
ActiveSurfaceContext,
|
|
17
30
|
ChannelCapabilities,
|
|
31
|
+
ChannelCommandContext,
|
|
18
32
|
InjectionMode,
|
|
19
33
|
} from "../daemon/conversation-runtime-assembly.js";
|
|
20
34
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
@@ -74,7 +88,32 @@ export type {
|
|
|
74
88
|
PluginShutdownContext,
|
|
75
89
|
} from "../plugin-api/types.js";
|
|
76
90
|
|
|
77
|
-
// ───
|
|
91
|
+
// ─── Middleware ──────────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Generic onion-style middleware. Each middleware may observe/modify the
|
|
95
|
+
* arguments, decide whether to call `next` (short-circuit) or return a
|
|
96
|
+
* synthetic result, and observe/modify the downstream result. `ctx` is the
|
|
97
|
+
* immutable per-turn {@link TurnContext}.
|
|
98
|
+
*/
|
|
99
|
+
export type Middleware<A, R> = (
|
|
100
|
+
args: A,
|
|
101
|
+
next: (args: A) => Promise<R>,
|
|
102
|
+
ctx: TurnContext,
|
|
103
|
+
) => Promise<R>;
|
|
104
|
+
|
|
105
|
+
// ─── Pipeline names ──────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Exhaustive list of pipeline slot names. New pipelines must be added here
|
|
109
|
+
* and in `DEFAULT_TIMEOUTS` (PR 12). The registry only understands these.
|
|
110
|
+
*/
|
|
111
|
+
export type PipelineName = "compaction" | "overflowReduce" | "circuitBreaker";
|
|
112
|
+
|
|
113
|
+
// ─── Per-pipeline args / results (placeholder shapes) ────────────────────────
|
|
114
|
+
// Concrete field-level types land in M2/M3 PRs as each pipeline is wrapped.
|
|
115
|
+
// Until then we expose `unknown`-tagged aliases so downstream code can name
|
|
116
|
+
// the types without depending on unstable internal shapes.
|
|
78
117
|
|
|
79
118
|
/**
|
|
80
119
|
* Full output of a single memory-graph retrieval — the object returned by
|
|
@@ -87,7 +126,186 @@ export type GraphMemoryResult = Awaited<
|
|
|
87
126
|
>;
|
|
88
127
|
|
|
89
128
|
/**
|
|
90
|
-
*
|
|
129
|
+
* Pipeline inputs for the `compaction` slot — the arguments the assistant
|
|
130
|
+
* would otherwise have passed to {@link ContextWindowManager.maybeCompact}.
|
|
131
|
+
*
|
|
132
|
+
* Typed via `unknown`-forwarded aliases to keep this module free of runtime
|
|
133
|
+
* imports from `context/window-manager.ts` (which would pull the full
|
|
134
|
+
* compaction machinery into anything that merely imports plugin types).
|
|
135
|
+
* The default compaction plugin re-casts back to the concrete types before
|
|
136
|
+
* delegating to the manager.
|
|
137
|
+
*/
|
|
138
|
+
export type CompactionArgs = {
|
|
139
|
+
/** The message history to consider for compaction. */
|
|
140
|
+
readonly messages: unknown;
|
|
141
|
+
/** Abort signal forwarded to the compaction summary call. */
|
|
142
|
+
readonly signal?: AbortSignal;
|
|
143
|
+
/** `ContextWindowCompactOptions` — options block forwarded verbatim. */
|
|
144
|
+
readonly options?: unknown;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Pipeline result for the `compaction` slot — the full
|
|
148
|
+
* {@link import("../context/window-manager.js").ContextWindowResult}
|
|
149
|
+
* object returned by `maybeCompact()`. Kept as `unknown` here for the
|
|
150
|
+
* same decoupling reason as {@link CompactionArgs}; consumers in
|
|
151
|
+
* `daemon/conversation-agent-loop.ts` cast back to the concrete shape.
|
|
152
|
+
*/
|
|
153
|
+
export type CompactionResult = unknown;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Input to the `overflowReduce` pipeline. Captures everything the reducer
|
|
157
|
+
* tier loop needs, including the message history, reducer configuration,
|
|
158
|
+
* and side-effect callbacks that bridge the pipeline back to the orchestrator's
|
|
159
|
+
* mutable per-turn state (context-window manager, activity emitter, runtime
|
|
160
|
+
* injection reassembly, memory reinjection).
|
|
161
|
+
*
|
|
162
|
+
* The callbacks are supplied by the orchestrator because the reducer loop
|
|
163
|
+
* needs to coordinate with state that lives on the `AgentLoopConversationContext`
|
|
164
|
+
* (message mutation, compaction event emission, circuit breaker tracking,
|
|
165
|
+
* injection block reassembly). Keeping them as explicit callbacks — rather
|
|
166
|
+
* than pulling the whole context into the pipeline — preserves the rule that
|
|
167
|
+
* `TurnContext` stays minimal and pipeline-agnostic.
|
|
168
|
+
*/
|
|
169
|
+
export interface OverflowReduceArgs {
|
|
170
|
+
/** Bare persisted message history (mutable copy — the default middleware
|
|
171
|
+
* applies reducer results in-place via the `applyMessages` callback). */
|
|
172
|
+
readonly messages: Message[];
|
|
173
|
+
/** Current run-time message array with runtime injections applied. */
|
|
174
|
+
readonly runMessages: Message[];
|
|
175
|
+
/** System prompt used for post-step token estimation. */
|
|
176
|
+
readonly systemPrompt: string;
|
|
177
|
+
/** Provider name used for token estimation (calibration provider key). */
|
|
178
|
+
readonly providerName: string;
|
|
179
|
+
/** Context window config (drives compaction behavior). */
|
|
180
|
+
readonly contextWindow: ContextWindowConfig;
|
|
181
|
+
/** Token budget the reducer must get below (preflight budget). */
|
|
182
|
+
readonly preflightBudget: number;
|
|
183
|
+
/** Tool-token overhead included in every estimation call. */
|
|
184
|
+
readonly toolTokenBudget?: number;
|
|
185
|
+
/** Maximum reducer iterations before the loop exits unconditionally. */
|
|
186
|
+
readonly maxAttempts: number;
|
|
187
|
+
/** Abort signal threaded through compaction calls. */
|
|
188
|
+
readonly abortSignal?: AbortSignal;
|
|
189
|
+
/**
|
|
190
|
+
* Compaction callback — the reducer never owns the ContextWindowManager
|
|
191
|
+
* instance. The orchestrator supplies this closure so the default plugin
|
|
192
|
+
* can delegate the forced-compaction tier without crossing the
|
|
193
|
+
* pipeline/infra boundary on its own.
|
|
194
|
+
*/
|
|
195
|
+
readonly compactFn: (
|
|
196
|
+
messages: Message[],
|
|
197
|
+
signal: AbortSignal | undefined,
|
|
198
|
+
options: unknown,
|
|
199
|
+
) => Promise<ContextWindowResult>;
|
|
200
|
+
/**
|
|
201
|
+
* Invoked before each reducer iteration to emit the `context_compacting`
|
|
202
|
+
* activity state. The orchestrator owns activity emission because the
|
|
203
|
+
* signal is trust/channel aware.
|
|
204
|
+
*/
|
|
205
|
+
readonly emitActivityState: () => void;
|
|
206
|
+
/**
|
|
207
|
+
* Invoked after each reducer step that produced a successful compaction.
|
|
208
|
+
* Handles circuit-breaker tracking, event emission, and context mutation.
|
|
209
|
+
* The pipeline passes back `didCompact` so the orchestrator can flip its
|
|
210
|
+
* `reducerCompacted` / `shouldInjectWorkspace` flags and the next
|
|
211
|
+
* re-injection uses the fresh messages.
|
|
212
|
+
*/
|
|
213
|
+
readonly onCompactionResult: (
|
|
214
|
+
result: ContextWindowResult,
|
|
215
|
+
compactedBasis?: Message[],
|
|
216
|
+
) => void | Promise<void>;
|
|
217
|
+
/**
|
|
218
|
+
* Invoked after each step to rebuild `runMessages` from the step's
|
|
219
|
+
* reduced history with the requested injection mode. The orchestrator
|
|
220
|
+
* owns this helper so the full per-turn injection options object doesn't
|
|
221
|
+
* leak into the pipeline surface. The plugin passes the current reduced
|
|
222
|
+
* messages array explicitly so the orchestrator doesn't need to read
|
|
223
|
+
* mutable shared state. Returns the new `runMessages`.
|
|
224
|
+
*
|
|
225
|
+
* Two distinct "did compact" signals are passed so the orchestrator can
|
|
226
|
+
* apply the correct per-iteration vs sticky gating:
|
|
227
|
+
* - `stepCompacted` — whether THIS iteration's reducer step produced a
|
|
228
|
+
* fresh compaction. Gates PKB / NOW re-injection: compaction strips the
|
|
229
|
+
* existing blocks, so only iterations that just compacted need the
|
|
230
|
+
* content re-threaded. Iterations that only truncated tool results or
|
|
231
|
+
* downgraded injections must NOT force a re-injection or the token
|
|
232
|
+
* count grows each round.
|
|
233
|
+
* - `accumulatedCompacted` — whether ANY iteration in this pipeline
|
|
234
|
+
* invocation has compacted. Gates `slackChronologicalMessages`
|
|
235
|
+
* suppression: once compaction has run, the captured Slack transcript
|
|
236
|
+
* snapshot would overwrite the compacted history, so it must stay
|
|
237
|
+
* suppressed for every subsequent iteration even if that iteration
|
|
238
|
+
* didn't re-compact.
|
|
239
|
+
*/
|
|
240
|
+
readonly reinjectForMode: (
|
|
241
|
+
messages: Message[],
|
|
242
|
+
mode: InjectionMode,
|
|
243
|
+
stepCompacted: boolean,
|
|
244
|
+
accumulatedCompacted: boolean,
|
|
245
|
+
) => Promise<Message[]>;
|
|
246
|
+
/**
|
|
247
|
+
* Invoked after each step to post-estimate the rebuilt `runMessages`.
|
|
248
|
+
* Pulled out so the orchestrator controls how estimation is performed
|
|
249
|
+
* (and which fields feed it) without the pipeline reimplementing it.
|
|
250
|
+
*/
|
|
251
|
+
readonly estimatePostInjection: (runMessages: Message[]) => number;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Output of the `overflowReduce` pipeline. */
|
|
255
|
+
export interface OverflowReduceResult {
|
|
256
|
+
/** Final reduced `ctx.messages` value (mutated in place by the reducer). */
|
|
257
|
+
readonly messages: Message[];
|
|
258
|
+
/** Final `runMessages` with re-applied runtime injections. */
|
|
259
|
+
readonly runMessages: Message[];
|
|
260
|
+
/** Final injection mode (may be `"minimal"` if the downgrade tier fired). */
|
|
261
|
+
readonly injectionMode: InjectionMode;
|
|
262
|
+
/** Accumulated reducer state at exit. */
|
|
263
|
+
readonly reducerState: ReducerState;
|
|
264
|
+
/** True if any step successfully compacted history. */
|
|
265
|
+
readonly reducerCompacted: boolean;
|
|
266
|
+
/** How many iterations of the tier loop executed. */
|
|
267
|
+
readonly attempts: number;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Arguments for the `circuitBreaker` pipeline.
|
|
272
|
+
*
|
|
273
|
+
* A single call pattern handles both querying and updating the breaker:
|
|
274
|
+
* - `{ key }` — query-only. Returns the current `{ open, cooldownRemainingMs? }`.
|
|
275
|
+
* - `{ key, outcome }` — update state, then return the post-update decision.
|
|
276
|
+
*
|
|
277
|
+
* `key` identifies the circuit bucket so independent circuits (e.g. per
|
|
278
|
+
* conversation, per provider) can coexist. The default compaction plugin
|
|
279
|
+
* uses `"compaction:<conversationId>"`.
|
|
280
|
+
*
|
|
281
|
+
* `state` is a pragmatic extension beyond the minimal `{ key, outcome? }`
|
|
282
|
+
* shape: the `Conversation` owns `consecutiveCompactionFailures` and
|
|
283
|
+
* `compactionCircuitOpenUntil` because dev-only playground routes read and
|
|
284
|
+
* mutate those fields directly. The default plugin reads/updates the same
|
|
285
|
+
* container so the pipeline stays a pure wrapper rather than forking state
|
|
286
|
+
* ownership.
|
|
287
|
+
*
|
|
288
|
+
* `onEvent` is optional — when provided, the default plugin emits
|
|
289
|
+
* `compaction_circuit_open` / `compaction_circuit_closed` transition events
|
|
290
|
+
* through it. Its parameter is narrowed to {@link CompactionCircuitEvent} (the
|
|
291
|
+
* only two messages this pipeline ever emits) rather than the full
|
|
292
|
+
* `ServerMessage` union, so a caller whose outbound channel can carry just
|
|
293
|
+
* these two events can satisfy it. Callers that only want to query without
|
|
294
|
+
* emitting can omit it.
|
|
295
|
+
*/
|
|
296
|
+
export type CircuitBreakerArgs = {
|
|
297
|
+
readonly key: string;
|
|
298
|
+
readonly outcome?: "success" | "failure";
|
|
299
|
+
readonly state: {
|
|
300
|
+
readonly conversationId: string;
|
|
301
|
+
consecutiveCompactionFailures: number;
|
|
302
|
+
compactionCircuitOpenUntil: number | null;
|
|
303
|
+
};
|
|
304
|
+
readonly onEvent?: (msg: CompactionCircuitEvent) => void;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* The complete set of transition events the `circuitBreaker` pipeline emits:
|
|
91
309
|
* `compaction_circuit_open` when the breaker trips and `compaction_circuit_closed`
|
|
92
310
|
* on the open→closed transition. Both are a subset of `ServerMessage`, so any
|
|
93
311
|
* existing `ServerMessage` sink remains assignable to a
|
|
@@ -97,6 +315,31 @@ export type CompactionCircuitEvent =
|
|
|
97
315
|
| CompactionCircuitOpenEvent
|
|
98
316
|
| CompactionCircuitClosedEvent;
|
|
99
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Result of a `circuitBreaker` pipeline invocation.
|
|
320
|
+
*
|
|
321
|
+
* - `open` — `true` when the breaker is currently tripped (auto paths must
|
|
322
|
+
* skip). `false` when closed (auto paths may proceed).
|
|
323
|
+
* - `cooldownRemainingMs` — when `open` is `true`, the number of ms until
|
|
324
|
+
* the breaker auto-closes (for informational display). Omitted when the
|
|
325
|
+
* breaker is closed.
|
|
326
|
+
*/
|
|
327
|
+
export type CircuitBreakerResult = {
|
|
328
|
+
readonly open: boolean;
|
|
329
|
+
readonly cooldownRemainingMs?: number;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Mapping from {@link PipelineName} to the middleware signature the registry
|
|
334
|
+
* expects for that slot. Used both to shape `Plugin.middleware` and to drive
|
|
335
|
+
* `getMiddlewaresFor<P>()` type narrowing in PR 13.
|
|
336
|
+
*/
|
|
337
|
+
export interface PipelineMiddlewareMap {
|
|
338
|
+
compaction: Middleware<CompactionArgs, CompactionResult>;
|
|
339
|
+
overflowReduce: Middleware<OverflowReduceArgs, OverflowReduceResult>;
|
|
340
|
+
circuitBreaker: Middleware<CircuitBreakerArgs, CircuitBreakerResult>;
|
|
341
|
+
}
|
|
342
|
+
|
|
100
343
|
// ─── TurnContext ─────────────────────────────────────────────────────────────
|
|
101
344
|
|
|
102
345
|
/**
|
|
@@ -122,6 +365,10 @@ export interface TurnInjectionInputs {
|
|
|
122
365
|
* context (unified turn context, etc.). Drives per-injector gating.
|
|
123
366
|
*/
|
|
124
367
|
readonly mode?: InjectionMode;
|
|
368
|
+
/** Disk-pressure cleanup-mode context or null to skip the warning. */
|
|
369
|
+
readonly diskPressureContext?: DiskPressureInjectionContext | null;
|
|
370
|
+
/** Workspace top-level context text (`<workspace>...`) or null to skip. */
|
|
371
|
+
readonly workspaceTopLevelContext?: string | null;
|
|
125
372
|
/** Pre-built unified-turn-context text (`<turn_context>...`) or null to skip. */
|
|
126
373
|
readonly unifiedTurnContext?: string | null;
|
|
127
374
|
/** Pre-built `<active_subagents>` block or null to skip. */
|
|
@@ -140,6 +387,18 @@ export interface TurnInjectionInputs {
|
|
|
140
387
|
* no focus block is appended.
|
|
141
388
|
*/
|
|
142
389
|
readonly slackActiveThreadFocusBlock?: string | null;
|
|
390
|
+
/**
|
|
391
|
+
* Active dashboard-surface context (read from `<active_workspace>`). Kept
|
|
392
|
+
* on the injection inputs bag (not its own injector) because it is
|
|
393
|
+
* orchestrator-owned surface state, not a default-chain element.
|
|
394
|
+
*/
|
|
395
|
+
readonly activeSurface?: ActiveSurfaceContext | null;
|
|
396
|
+
/** Channel command context (e.g. Telegram /start) or null to skip. */
|
|
397
|
+
readonly channelCommandContext?: ChannelCommandContext | null;
|
|
398
|
+
/** Voice call-control prompt or null to skip. */
|
|
399
|
+
readonly voiceCallControlPrompt?: string | null;
|
|
400
|
+
/** Gateway-provided transport hints (e.g. Slack thread context). */
|
|
401
|
+
readonly transportHints?: string[] | null;
|
|
143
402
|
/**
|
|
144
403
|
* When true, inject the `<non_interactive_context>` block so the model
|
|
145
404
|
* knows no human is present to answer clarification questions.
|
|
@@ -165,12 +424,18 @@ export interface TurnInjectionInputs {
|
|
|
165
424
|
}> | null;
|
|
166
425
|
}
|
|
167
426
|
|
|
427
|
+
export interface DiskPressureInjectionContext {
|
|
428
|
+
/** True when the current turn is allowed to run only for storage cleanup. */
|
|
429
|
+
readonly cleanupModeActive: boolean;
|
|
430
|
+
}
|
|
431
|
+
|
|
168
432
|
/**
|
|
169
|
-
* Per-turn execution context threaded
|
|
170
|
-
* consumers that need turn-level identity.
|
|
433
|
+
* Per-turn execution context threaded through every middleware invocation.
|
|
171
434
|
*
|
|
172
435
|
* Combines turn-level identifiers (`requestId`, `conversationId`,
|
|
173
|
-
* `turnIndex`)
|
|
436
|
+
* `turnIndex`), the optionally-bound `pluginName` (set by the pipeline
|
|
437
|
+
* runner when invoking a specific plugin's middleware, for error
|
|
438
|
+
* attribution), and the canonical {@link TrustContext} that carries trust
|
|
174
439
|
* class and channel identity for the inbound actor.
|
|
175
440
|
*
|
|
176
441
|
* `TrustContext` is re-exposed here (rather than redefined) so the plugin
|
|
@@ -183,42 +448,51 @@ export interface TurnContext {
|
|
|
183
448
|
conversationId: string;
|
|
184
449
|
/** 0-based turn index within the conversation. */
|
|
185
450
|
turnIndex: number;
|
|
451
|
+
/**
|
|
452
|
+
* When the pipeline runner is executing a specific plugin's middleware,
|
|
453
|
+
* this is set to that plugin's name so downstream code (error wrapping,
|
|
454
|
+
* telemetry) can attribute work accurately.
|
|
455
|
+
*/
|
|
456
|
+
pluginName?: string;
|
|
186
457
|
/** Trust classification and channel identity for the inbound actor. */
|
|
187
458
|
trust: TrustContext;
|
|
188
459
|
/**
|
|
189
460
|
* Optional handle to the conversation's {@link ContextWindowManager}.
|
|
190
461
|
*
|
|
191
|
-
* Attached by the orchestrator
|
|
192
|
-
* defer to the real compaction machinery
|
|
193
|
-
*
|
|
462
|
+
* Attached by the orchestrator when building the per-turn context for
|
|
463
|
+
* pipeline invocations that need to defer to the real compaction machinery
|
|
464
|
+
* (notably the default `compaction` plugin). Pipelines that never touch
|
|
465
|
+
* compaction can ignore this field; the default compaction plugin throws
|
|
466
|
+
* a {@link PluginExecutionError} if it is missing, which keeps the failure
|
|
467
|
+
* attributed to the plugin rather than surfacing as a late NPE downstream.
|
|
194
468
|
*
|
|
195
469
|
* Declared as an optional typed field so plugin code can read it without a
|
|
196
|
-
* lenient cast. The optional shape is load-bearing:
|
|
197
|
-
* contexts and other non-compaction call sites still
|
|
198
|
-
* `TurnContext` literals without attaching a manager.
|
|
470
|
+
* lenient cast. The optional shape is load-bearing: pipeline runner tests,
|
|
471
|
+
* synthesized handler contexts, and other non-compaction call sites still
|
|
472
|
+
* construct valid `TurnContext` literals without attaching a manager.
|
|
199
473
|
*/
|
|
200
474
|
contextWindowManager?: ContextWindowManager;
|
|
201
475
|
/**
|
|
202
476
|
* Per-turn injection inputs consumed by the default injector chain.
|
|
203
477
|
*
|
|
204
|
-
* Omitted for call sites that don't drive runtime injection (
|
|
205
|
-
* handler contexts, some background jobs). Each default
|
|
206
|
-
* missing/absent fields as "no injection on this turn", so
|
|
207
|
-
* without `injectionInputs` produces an empty injection chain.
|
|
478
|
+
* Omitted for call sites that don't drive runtime injection (pipeline-runner
|
|
479
|
+
* tests, synthesized handler contexts, some background jobs). Each default
|
|
480
|
+
* injector treats missing/absent fields as "no injection on this turn", so
|
|
481
|
+
* a context without `injectionInputs` produces an empty injection chain.
|
|
208
482
|
*/
|
|
209
483
|
injectionInputs?: TurnInjectionInputs;
|
|
210
484
|
/**
|
|
211
|
-
* The {@link LLMCallSite} this turn belongs to —
|
|
212
|
-
* user-facing conversational reply, or the specific
|
|
213
|
-
* (`"compactionAgent"`, `"subagentSpawn"`,
|
|
214
|
-
* `"conversationTitle"`, …) when the agent loop is
|
|
215
|
-
* that happens to share the same `conversationId`.
|
|
485
|
+
* The {@link LLMCallSite} this turn's pipeline work belongs to —
|
|
486
|
+
* `"mainAgent"` for the user-facing conversational reply, or the specific
|
|
487
|
+
* background/utility site (`"compactionAgent"`, `"subagentSpawn"`,
|
|
488
|
+
* `"memoryConsolidation"`, `"conversationTitle"`, …) when the agent loop is
|
|
489
|
+
* driving non-main work that happens to share the same `conversationId`.
|
|
216
490
|
*
|
|
217
|
-
* Lets {@link Injector}s scope their behaviour to
|
|
218
|
-
* out of background turns, which `onEvent` presence
|
|
219
|
-
* (compaction and subagent loops also stream).
|
|
220
|
-
* don't tag a site (synthesized test contexts);
|
|
221
|
-
* absence conservatively.
|
|
491
|
+
* Lets {@link Injector}s and pipeline middleware scope their behaviour to
|
|
492
|
+
* the main reply and stay out of background turns, which `onEvent` presence
|
|
493
|
+
* alone cannot distinguish (compaction and subagent loops also stream).
|
|
494
|
+
* Omitted by call sites that don't tag a site (synthesized test contexts);
|
|
495
|
+
* consumers should treat absence conservatively.
|
|
222
496
|
*/
|
|
223
497
|
callSite?: LLMCallSite;
|
|
224
498
|
}
|
|
@@ -401,7 +675,7 @@ export type PluginHooks = Record<string, PluginHookFn<any>>;
|
|
|
401
675
|
|
|
402
676
|
/**
|
|
403
677
|
* A registered plugin. Every field besides `manifest` is optional — a plugin
|
|
404
|
-
* may contribute any combination of
|
|
678
|
+
* may contribute any combination of middleware and model-visible
|
|
405
679
|
* capabilities. Lifecycle hooks live under `hooks`.
|
|
406
680
|
*/
|
|
407
681
|
export interface Plugin {
|
|
@@ -423,13 +697,43 @@ export interface Plugin {
|
|
|
423
697
|
routes?: PluginRouteRegistration[];
|
|
424
698
|
/** Skill registrations loaded at startup. */
|
|
425
699
|
skills?: PluginSkillRegistration[];
|
|
700
|
+
/**
|
|
701
|
+
* Named middleware slots. At most one middleware per slot per plugin.
|
|
702
|
+
* The registry composes multiple plugins' middleware for a slot in
|
|
703
|
+
* registration order (outermost first).
|
|
704
|
+
*/
|
|
705
|
+
middleware?: Partial<PipelineMiddlewareMap>;
|
|
426
706
|
}
|
|
427
707
|
|
|
428
708
|
// ─── Errors ──────────────────────────────────────────────────────────────────
|
|
429
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Thrown by the pipeline runner when a plugin's middleware exceeds the
|
|
712
|
+
* pipeline's configured timeout. Carries the pipeline name, the offending
|
|
713
|
+
* plugin (if known), and the elapsed-milliseconds budget that was breached.
|
|
714
|
+
*/
|
|
715
|
+
export class PluginTimeoutError extends AssistantError {
|
|
716
|
+
constructor(
|
|
717
|
+
public readonly pipeline: PipelineName,
|
|
718
|
+
public readonly pluginName: string | undefined,
|
|
719
|
+
public readonly elapsedMs: number,
|
|
720
|
+
options?: { cause?: unknown },
|
|
721
|
+
) {
|
|
722
|
+
super(
|
|
723
|
+
`Plugin pipeline '${pipeline}' timed out after ${elapsedMs}ms${
|
|
724
|
+
pluginName ? ` (offending plugin: ${pluginName})` : ""
|
|
725
|
+
}`,
|
|
726
|
+
ErrorCode.INTERNAL_ERROR,
|
|
727
|
+
options,
|
|
728
|
+
);
|
|
729
|
+
this.name = "PluginTimeoutError";
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
430
733
|
/**
|
|
431
734
|
* Thrown by registry and bootstrap for plugin lifecycle errors — registration
|
|
432
|
-
* validation failures, API-version mismatches, init throw-outs.
|
|
735
|
+
* validation failures, API-version mismatches, init throw-outs. Distinct from
|
|
736
|
+
* {@link PluginTimeoutError} so callers can discriminate.
|
|
433
737
|
*/
|
|
434
738
|
export class PluginExecutionError extends AssistantError {
|
|
435
739
|
constructor(
|