@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
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
* `assignPages`, and `invalidateLanes` without process-global module mocks.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import { isAssistantFeatureFlagEnabled } from "
|
|
29
|
-
import type { AssistantConfig } from "
|
|
30
|
-
import {
|
|
31
|
-
import
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
28
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
29
|
+
import type { AssistantConfig } from "../../config/types.js";
|
|
30
|
+
import { getLogger } from "../../util/logger.js";
|
|
31
|
+
import { getWorkspaceDir } from "../../util/platform.js";
|
|
32
|
+
import { getMemoryCheckpoint, setMemoryCheckpoint } from "../checkpoints.js";
|
|
33
|
+
import type { MemoryJob } from "../jobs-store.js";
|
|
34
|
+
import { getPageIndex } from "../v2/page-index.js";
|
|
35
|
+
import { listPages, readPage, writePage } from "../v2/page-store.js";
|
|
36
36
|
import { assignPages as realAssignPages } from "./assign.js";
|
|
37
37
|
import { invalidateLanes as realInvalidateLanes } from "./shadow-plugin.js";
|
|
38
38
|
import { loadLeafTree as realLoadLeafTree, resolveDataDir } from "./tree.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getWorkspaceDir } from "../../util/platform.js";
|
|
2
|
+
import { readPage, renderPageContent } from "../v2/page-store.js";
|
|
3
3
|
import { renderCapabilityContent } from "./capabilities.js";
|
|
4
4
|
import type { Slug } from "./types.js";
|
|
5
5
|
|
|
@@ -38,9 +38,9 @@ import { join, relative, sep } from "node:path";
|
|
|
38
38
|
|
|
39
39
|
import { parse as parseYaml } from "yaml";
|
|
40
40
|
|
|
41
|
-
import {
|
|
42
|
-
import
|
|
43
|
-
import {
|
|
41
|
+
import type { Provider } from "../../providers/types.js";
|
|
42
|
+
import { getLogger } from "../../util/logger.js";
|
|
43
|
+
import { listPages, readPage, writePage } from "../v2/page-store.js";
|
|
44
44
|
import { assignPages } from "./assign.js";
|
|
45
45
|
import { loadCore } from "./core.js";
|
|
46
46
|
import { invalidateLanes } from "./shadow-plugin.js";
|
|
@@ -33,9 +33,9 @@ import { z } from "zod";
|
|
|
33
33
|
import {
|
|
34
34
|
extractToolUse,
|
|
35
35
|
getConfiguredProvider,
|
|
36
|
-
} from "
|
|
37
|
-
import type { Message, ToolDefinition } from "
|
|
38
|
-
import { getLogger } from "
|
|
36
|
+
} from "../../providers/provider-send-message.js";
|
|
37
|
+
import type { Message, ToolDefinition } from "../../providers/types.js";
|
|
38
|
+
import { getLogger } from "../../util/logger.js";
|
|
39
39
|
import { retryForResult } from "./llm-retry.js";
|
|
40
40
|
import { cachedTextBlock } from "./provider-blocks.js";
|
|
41
41
|
import type { LeafPath, LeafTree, TurnContext } from "./types.js";
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* across turns) and can't be reproduced after the fact.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { MemoryV3SelectionLog } from "
|
|
11
|
-
import { isAssistantFeatureFlagEnabled } from "
|
|
12
|
-
import { getConfig } from "
|
|
13
|
-
import { getDb, getSqliteFrom } from "
|
|
10
|
+
import type { MemoryV3SelectionLog } from "../../api/responses/memory-v3-selection-log.js";
|
|
11
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
12
|
+
import { getConfig } from "../../config/loader.js";
|
|
13
|
+
import { getDb, getSqliteFrom } from "../db-connection.js";
|
|
14
14
|
import { renderV3PageContent } from "./page-content.js";
|
|
15
15
|
import { renderMemoryBlock } from "./render-injection.js";
|
|
16
16
|
import type { Slug } from "./types.js";
|
|
@@ -33,10 +33,10 @@ import { z } from "zod";
|
|
|
33
33
|
import {
|
|
34
34
|
extractToolUse,
|
|
35
35
|
getConfiguredProvider,
|
|
36
|
-
} from "
|
|
37
|
-
import type { Message, ToolDefinition } from "
|
|
38
|
-
import { getLogger } from "
|
|
39
|
-
import { mapLimit } from "
|
|
36
|
+
} from "../../providers/provider-send-message.js";
|
|
37
|
+
import type { Message, ToolDefinition } from "../../providers/types.js";
|
|
38
|
+
import { getLogger } from "../../util/logger.js";
|
|
39
|
+
import { mapLimit } from "../../util/map-limit.js";
|
|
40
40
|
import { retryForResult } from "./llm-retry.js";
|
|
41
41
|
import { cachedTextBlock } from "./provider-blocks.js";
|
|
42
42
|
import { membersOf } from "./tree.js";
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Memory v3 — flag-gated shadow/live
|
|
2
|
+
* Memory v3 — flag-gated shadow/live injector.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `memory_v3_selections`. Two flags gate
|
|
4
|
+
* An {@link Injector} that runs the v3 orchestrator each turn and
|
|
5
|
+
* records its selection set to `memory_v3_selections`. Two flags gate its
|
|
6
|
+
* injection behavior:
|
|
6
7
|
*
|
|
7
|
-
* - `memory-v3-shadow` (live OFF): observation-only.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `<memory>` block and returns it at v2's dynamic-memory placement
|
|
8
|
+
* - `memory-v3-shadow` (and live OFF): observation-only. `produce()` returns
|
|
9
|
+
* `null`, so v2 injection is bit-for-bit identical whether the flag is on
|
|
10
|
+
* or off — the only difference is the side-effect telemetry write.
|
|
11
|
+
* - `memory-v3-live`: live injection. `produce()` additionally renders the
|
|
12
|
+
* working-set selection into a `<memory>` block via {@link renderMemoryBlock}
|
|
13
|
+
* and returns it as an injection block at v2's dynamic-memory placement
|
|
14
14
|
* (`after-memory-prefix`). Selections are still logged.
|
|
15
|
-
* - both OFF:
|
|
15
|
+
* - both OFF: `produce()` returns `null` and skips orchestration entirely.
|
|
16
16
|
*
|
|
17
17
|
* On each turn (either flag on):
|
|
18
18
|
* 1. Lazy-init the v3 lanes ONCE across the whole process (leaf tree, core
|
|
@@ -22,45 +22,54 @@
|
|
|
22
22
|
* 3. Run {@link orchestrate} and record its selection set to
|
|
23
23
|
* `memory_v3_selections` with a best-effort lane attribution.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* Everything after the flag read is wrapped in try/catch — any failure is
|
|
26
|
+
* logged and swallowed so it can never affect the live turn. In live mode a
|
|
27
|
+
* failure returns `null` (no v3 injection); v2 suppression keys off BOTH the
|
|
28
|
+
* flag AND whether `produce()` actually returned a block, so a v3 failure (or
|
|
29
|
+
* empty selection) falls back to v2 memory rather than dropping all memory.
|
|
29
30
|
*/
|
|
30
31
|
|
|
31
32
|
import { existsSync, readFileSync } from "node:fs";
|
|
32
33
|
|
|
33
|
-
import { isAssistantFeatureFlagEnabled } from "
|
|
34
|
-
import { getConfig } from "
|
|
35
|
-
import type { AssistantConfig } from "
|
|
36
|
-
import { getMessages } from "
|
|
37
|
-
import { getDb, getSqliteFrom } from "
|
|
38
|
-
import { stringifyMessageContent } from "
|
|
39
|
-
import {
|
|
40
|
-
|
|
34
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
35
|
+
import { getConfig } from "../../config/loader.js";
|
|
36
|
+
import type { AssistantConfig } from "../../config/schema.js";
|
|
37
|
+
import { getMessages } from "../../memory/conversation-crud.js";
|
|
38
|
+
import { getDb, getSqliteFrom } from "../../memory/db-connection.js";
|
|
39
|
+
import { stringifyMessageContent } from "../../memory/message-content.js";
|
|
40
|
+
import {
|
|
41
|
+
type InjectionBlock,
|
|
42
|
+
type Injector,
|
|
43
|
+
type TurnContext as PluginTurnContext,
|
|
44
|
+
} from "../../plugins/types.js";
|
|
45
|
+
import { getLogger } from "../../util/logger.js";
|
|
41
46
|
import {
|
|
42
47
|
getWorkspaceDir,
|
|
43
48
|
getWorkspacePromptPath,
|
|
44
|
-
} from "
|
|
45
|
-
import { stripCommentLines } from "
|
|
49
|
+
} from "../../util/platform.js";
|
|
50
|
+
import { stripCommentLines } from "../../util/strip-comment-lines.js";
|
|
51
|
+
import { getPageIndex } from "../v2/page-index.js";
|
|
46
52
|
import { injectCapabilitiesLeaf, isCapabilitySlug } from "./capabilities.js";
|
|
47
53
|
import { loadCore } from "./core.js";
|
|
48
54
|
import type { NeedleIndex } from "./needle.js";
|
|
49
55
|
import { buildNeedleIndex } from "./needle.js";
|
|
50
56
|
import type { OrchestrateResult } from "./orchestrate.js";
|
|
51
57
|
import { orchestrate } from "./orchestrate.js";
|
|
58
|
+
import { renderV3PageContent } from "./page-content.js";
|
|
59
|
+
import { renderMemoryBlock } from "./render-injection.js";
|
|
52
60
|
import { coreSlugs, loadLeafTree, resolveDataDir } from "./tree.js";
|
|
53
61
|
import {
|
|
54
62
|
type LeafPath,
|
|
55
63
|
type LeafTree,
|
|
64
|
+
MEMORY_V3_BLOCK_ID,
|
|
56
65
|
type SelectionSource,
|
|
57
66
|
type Slug,
|
|
58
67
|
type TurnContext,
|
|
59
68
|
} from "./types.js";
|
|
60
69
|
import { WorkingSet } from "./working-set.js";
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
|
|
72
|
+
const MEMORY_V3_LIVE = "memory-v3-live" as const;
|
|
64
73
|
|
|
65
74
|
const log = getLogger("memory-v3-shadow");
|
|
66
75
|
|
|
@@ -301,7 +310,7 @@ function writeSelections(
|
|
|
301
310
|
* failures are logged and swallowed (returning `null`) so the live turn is
|
|
302
311
|
* unaffected. Returns `null` when there is no user message to route on.
|
|
303
312
|
*/
|
|
304
|
-
|
|
313
|
+
async function observeTurn(
|
|
305
314
|
conversationId: string,
|
|
306
315
|
turnIndex: number,
|
|
307
316
|
): Promise<OrchestrateResult | null> {
|
|
@@ -347,3 +356,56 @@ export async function runShadowObservation(
|
|
|
347
356
|
if (!isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, getConfig())) return;
|
|
348
357
|
await observeTurn(conversationId, turnIndex);
|
|
349
358
|
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* The v3 injector. Reads both flags:
|
|
362
|
+
* - `memory-v3-live` on → orchestrate, log, render the working-set selection
|
|
363
|
+
* into a `<memory>` block, and return it at v2's dynamic-memory placement.
|
|
364
|
+
* - `memory-v3-shadow` on (live off) → orchestrate + log only, return `null`.
|
|
365
|
+
* - both off → return `null` (no orchestration).
|
|
366
|
+
*
|
|
367
|
+
* Empty selection and any failure return `null` (no v3 injection). v2
|
|
368
|
+
* suppression keys off BOTH the flag AND this return value, so a `null` here
|
|
369
|
+
* (failure or empty selection) falls back to v2 memory rather than dropping all
|
|
370
|
+
* memory.
|
|
371
|
+
*/
|
|
372
|
+
export const memoryV3Injector: Injector = {
|
|
373
|
+
name: "memory-v3-shadow",
|
|
374
|
+
// High order so it sorts last; the live `<memory>` block uses the
|
|
375
|
+
// after-memory-prefix placement so it lands at the memory boundary regardless
|
|
376
|
+
// of this sort key, which only orders content-producing injectors.
|
|
377
|
+
order: 1000,
|
|
378
|
+
async produce(ctx: PluginTurnContext): Promise<InjectionBlock | null> {
|
|
379
|
+
const config = getConfig();
|
|
380
|
+
const live = isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config);
|
|
381
|
+
const shadow = isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config);
|
|
382
|
+
if (!live && !shadow) return null;
|
|
383
|
+
|
|
384
|
+
const result = await observeTurn(ctx.conversationId, ctx.turnIndex);
|
|
385
|
+
if (!live || !result) return null;
|
|
386
|
+
|
|
387
|
+
try {
|
|
388
|
+
// `renderMemoryBlock` returns "" for an empty selection; inject nothing.
|
|
389
|
+
const text = await renderMemoryBlock(
|
|
390
|
+
result.finalInjection,
|
|
391
|
+
renderV3PageContent,
|
|
392
|
+
);
|
|
393
|
+
if (text.length === 0) return null;
|
|
394
|
+
return {
|
|
395
|
+
id: MEMORY_V3_BLOCK_ID,
|
|
396
|
+
text,
|
|
397
|
+
// Mirror v2's dynamic `<memory>` block placement.
|
|
398
|
+
placement: "after-memory-prefix",
|
|
399
|
+
};
|
|
400
|
+
} catch (err) {
|
|
401
|
+
log.warn(
|
|
402
|
+
{
|
|
403
|
+
err: err instanceof Error ? err.message : String(err),
|
|
404
|
+
conversationId: ctx.conversationId,
|
|
405
|
+
},
|
|
406
|
+
"memory-v3 live render failed (non-fatal) — falling back to v2",
|
|
407
|
+
);
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
};
|
package/src/plugin-api/index.ts
CHANGED
|
@@ -34,6 +34,11 @@
|
|
|
34
34
|
* for both plugin tool files and workspace tool files)
|
|
35
35
|
* - {@link ToolContext} — passed to a plugin tool's `execute` method
|
|
36
36
|
* - {@link ToolExecutionResult} — return shape of a plugin tool's `execute`
|
|
37
|
+
*
|
|
38
|
+
* Pipeline-argument types (`MemoryArgs`, `CompactionArgs`, etc.) currently
|
|
39
|
+
* live in `assistant/src/plugins/types.ts` and have not yet migrated into
|
|
40
|
+
* this package. A follow-up PR will move them into this surface as the
|
|
41
|
+
* per-pipeline schemas stabilize.
|
|
37
42
|
*/
|
|
38
43
|
|
|
39
44
|
export type { HookName } from "./constants.js";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CircuitBreakerArgs,
|
|
3
|
+
CircuitBreakerResult,
|
|
4
|
+
Middleware,
|
|
5
|
+
} from "../../../types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Consecutive failures required to trip the breaker. Matches the legacy
|
|
9
|
+
* `COMPACTION_CIRCUIT_FAILURE_THRESHOLD` in `conversation-agent-loop.ts`.
|
|
10
|
+
*/
|
|
11
|
+
export const COMPACTION_CIRCUIT_FAILURE_THRESHOLD = 3;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Cooldown window after the breaker trips, during which auto-compaction is
|
|
15
|
+
* suspended. Matches the legacy `COMPACTION_CIRCUIT_COOLDOWN_MS`.
|
|
16
|
+
*/
|
|
17
|
+
export const COMPACTION_CIRCUIT_COOLDOWN_MS = 60 * 60 * 1000;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default middleware for the `circuitBreaker` pipeline. A thin wrapper over the
|
|
21
|
+
* state container passed in `CircuitBreakerArgs.state`:
|
|
22
|
+
*
|
|
23
|
+
* - `{ key }` — query. Defers to `next` for the current
|
|
24
|
+
* `{ open, cooldownRemainingMs? }`.
|
|
25
|
+
* - `{ key, outcome }` — update state based on outcome, then defer to `next`
|
|
26
|
+
* for the post-update decision. A run of three failures trips the breaker;
|
|
27
|
+
* any non-failure outcome resets both the counter and the cooldown timestamp.
|
|
28
|
+
*
|
|
29
|
+
* Event emission preserves the existing `trackCompactionOutcome` behavior:
|
|
30
|
+
* `compaction_circuit_open` fires once when the counter first reaches the
|
|
31
|
+
* threshold while the circuit is dormant; `compaction_circuit_closed` fires
|
|
32
|
+
* only on the open→closed transition.
|
|
33
|
+
*/
|
|
34
|
+
const circuitBreaker: Middleware<CircuitBreakerArgs, CircuitBreakerResult> =
|
|
35
|
+
async function circuitBreaker(args, next) {
|
|
36
|
+
const { outcome, state, onEvent } = args;
|
|
37
|
+
|
|
38
|
+
// Update branch — mutate state first, then defer to the downstream
|
|
39
|
+
// chain (or terminal) for the decision so outer observers still see
|
|
40
|
+
// the fully-processed outcome. Separating state mutation from
|
|
41
|
+
// decision computation also keeps this middleware composable: an
|
|
42
|
+
// outer plugin may wrap the invocation to observe both the pre-update
|
|
43
|
+
// args and the post-update result.
|
|
44
|
+
if (outcome !== undefined) {
|
|
45
|
+
if (outcome === "failure") {
|
|
46
|
+
state.consecutiveCompactionFailures += 1;
|
|
47
|
+
// Treat a stale/expired open-until timestamp the same as null so
|
|
48
|
+
// a new 3-strike window can re-open the circuit after the prior
|
|
49
|
+
// cooldown elapses. Without this, subsequent trips would no-op
|
|
50
|
+
// because `compactionCircuitOpenUntil` remains set to a past
|
|
51
|
+
// timestamp even though the breaker is effectively closed.
|
|
52
|
+
const circuitDormant =
|
|
53
|
+
state.compactionCircuitOpenUntil === null ||
|
|
54
|
+
Date.now() >= state.compactionCircuitOpenUntil;
|
|
55
|
+
if (
|
|
56
|
+
state.consecutiveCompactionFailures >=
|
|
57
|
+
COMPACTION_CIRCUIT_FAILURE_THRESHOLD &&
|
|
58
|
+
circuitDormant
|
|
59
|
+
) {
|
|
60
|
+
const openUntil = Date.now() + COMPACTION_CIRCUIT_COOLDOWN_MS;
|
|
61
|
+
state.compactionCircuitOpenUntil = openUntil;
|
|
62
|
+
if (onEvent) {
|
|
63
|
+
onEvent({
|
|
64
|
+
type: "compaction_circuit_open",
|
|
65
|
+
conversationId: state.conversationId,
|
|
66
|
+
reason: "3_consecutive_failures",
|
|
67
|
+
openUntil,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// Emit only on the open→closed transition; firing on the common
|
|
73
|
+
// closed→closed case would be noise.
|
|
74
|
+
const wasOpen = state.compactionCircuitOpenUntil !== null;
|
|
75
|
+
state.consecutiveCompactionFailures = 0;
|
|
76
|
+
state.compactionCircuitOpenUntil = null;
|
|
77
|
+
if (wasOpen && onEvent) {
|
|
78
|
+
onEvent({
|
|
79
|
+
type: "compaction_circuit_closed",
|
|
80
|
+
conversationId: state.conversationId,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Defer to downstream (the terminal, in the default registration, but
|
|
87
|
+
// potentially another plugin in a customized chain) for the final
|
|
88
|
+
// decision. The terminal's implementation is the canonical read of
|
|
89
|
+
// the (now-updated) state container.
|
|
90
|
+
return next(args);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export default circuitBreaker;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "default-
|
|
2
|
+
"name": "default-circuit-breaker",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"description": "First-party default plugin
|
|
4
|
+
"description": "First-party default plugin wrapping the assistant's built-in circuit-breaker pipeline with a passthrough implementation.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `circuitBreaker` plugin.
|
|
3
|
+
*
|
|
4
|
+
* Replicates the inline compaction circuit-breaker logic that previously
|
|
5
|
+
* lived in `daemon/conversation-agent-loop.ts`: three consecutive summary-LLM
|
|
6
|
+
* failures open the circuit for a one-hour cooldown, and any successful
|
|
7
|
+
* compaction resets the counter.
|
|
8
|
+
*
|
|
9
|
+
* The plugin is a thin wrapper over the state container passed in
|
|
10
|
+
* `CircuitBreakerArgs.state`. The {@link Conversation} owns the underlying
|
|
11
|
+
* fields (`consecutiveCompactionFailures`, `compactionCircuitOpenUntil`)
|
|
12
|
+
* because dev-only playground routes (`POST /playground/reset-compaction-circuit`,
|
|
13
|
+
* `POST /playground/inject-compaction-failures`) read and mutate them
|
|
14
|
+
* directly. Keeping ownership on the conversation lets this plugin stay a
|
|
15
|
+
* pure wrapper while preserving those hatches.
|
|
16
|
+
*
|
|
17
|
+
* The `key` parameter is carried through for multi-circuit futures but the
|
|
18
|
+
* default plugin currently bundles all circuit state into the `state`
|
|
19
|
+
* container; the key is attached to the log record via the pipeline runner.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { type Plugin } from "../../types.js";
|
|
23
|
+
import circuitBreaker from "./middlewares/circuitBreaker.js";
|
|
24
|
+
import pkg from "./package.json" with { type: "json" };
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Default plugin registered at daemon startup. Consumers negotiate against
|
|
28
|
+
* `circuitBreakerApi@v1` via the registry's capability table.
|
|
29
|
+
*/
|
|
30
|
+
export const defaultCircuitBreakerPlugin: Plugin = {
|
|
31
|
+
manifest: {
|
|
32
|
+
name: pkg.name,
|
|
33
|
+
version: pkg.version,
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
middleware: {
|
|
37
|
+
circuitBreaker,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CompactionArgs,
|
|
3
|
+
CompactionResult,
|
|
4
|
+
Middleware,
|
|
5
|
+
} from "../../../types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Passthrough middleware for the `compaction` pipeline. Forwards to
|
|
9
|
+
* `next(args)` so any custom plugins layered outside still run; when this is
|
|
10
|
+
* the only middleware, `next` is the terminal handler (`../terminal.ts`) and
|
|
11
|
+
* returns the real compaction output.
|
|
12
|
+
*
|
|
13
|
+
* Defaults register at the OUTERMOST onion position, so deciding here without
|
|
14
|
+
* calling `next` would shadow every later-registered plugin. Routing through
|
|
15
|
+
* `next(args)` lets user middleware participate normally.
|
|
16
|
+
*/
|
|
17
|
+
const defaultCompactionMiddleware: Middleware<
|
|
18
|
+
CompactionArgs,
|
|
19
|
+
CompactionResult
|
|
20
|
+
> = async function defaultCompaction(args, next, ctx) {
|
|
21
|
+
void ctx;
|
|
22
|
+
return next(args);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default defaultCompactionMiddleware;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "default-compaction",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"description": "First-party default plugin
|
|
4
|
+
"description": "First-party default plugin wrapping the assistant's built-in compaction pipeline with a passthrough implementation.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Default `compaction` plugin.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The plugin's middleware is a passthrough — it calls `next(args)` and returns
|
|
5
|
+
* the result unchanged. The actual compaction lives in the terminal handler in
|
|
6
|
+
* `./terminal.ts`, which is wired in as the pipeline's `terminal` argument by
|
|
7
|
+
* the `runPipeline` call site in `daemon/conversation-agent-loop.ts`. This
|
|
8
|
+
* separation matters: the default plugin is registered before any user plugin
|
|
9
|
+
* (defaults load first in `bootstrapPlugins()`), which puts it at the
|
|
10
|
+
* OUTERMOST position of the onion chain. If the default middleware were to
|
|
11
|
+
* invoke the terminal directly without calling `next`, it would shadow every
|
|
12
|
+
* later-registered plugin. Routing through `next(args)` lets user middleware
|
|
13
|
+
* participate normally.
|
|
14
|
+
*
|
|
15
|
+
* Design doc: `.private/plans/agent-plugin-system.md` (PR 25).
|
|
9
16
|
*/
|
|
10
17
|
|
|
11
18
|
import { type Plugin } from "../../types.js";
|
|
19
|
+
import defaultCompactionMiddleware from "./middlewares/compaction.js";
|
|
12
20
|
import pkg from "./package.json" with { type: "json" };
|
|
13
21
|
|
|
14
22
|
/**
|
|
15
|
-
* Manifest for the default compaction plugin. The
|
|
16
|
-
* `daemon/external-plugins-bootstrap.ts` before
|
|
17
|
-
* plugin `init()` hooks.
|
|
23
|
+
* Manifest + middleware wiring for the default compaction plugin. The
|
|
24
|
+
* registration happens in `daemon/external-plugins-bootstrap.ts` before
|
|
25
|
+
* {@link bootstrapPlugins} fires plugin `init()` hooks.
|
|
18
26
|
*/
|
|
19
27
|
export const defaultCompactionPlugin: Plugin = {
|
|
20
28
|
manifest: {
|
|
21
29
|
name: pkg.name,
|
|
22
30
|
version: pkg.version,
|
|
23
31
|
},
|
|
32
|
+
middleware: {
|
|
33
|
+
compaction: defaultCompactionMiddleware,
|
|
34
|
+
},
|
|
24
35
|
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `compaction` behavior: summarizes conversation history when the
|
|
3
|
+
* context window fills up.
|
|
4
|
+
*
|
|
5
|
+
* This module is side-effect free: importing it does not register any plugin.
|
|
6
|
+
*
|
|
7
|
+
* Delegates to the orchestrator's existing {@link ContextWindowManager}
|
|
8
|
+
* instance, read from `ctx.contextWindowManager` on the {@link TurnContext} as
|
|
9
|
+
* a typed optional field. The orchestrator is responsible for attaching that
|
|
10
|
+
* handle to the per-turn context. If the handle is missing, this throws a
|
|
11
|
+
* {@link PluginExecutionError} so the bug surfaces with clear attribution
|
|
12
|
+
* instead of a late `undefined.maybeCompact is not a function`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type {
|
|
16
|
+
ContextWindowCompactOptions,
|
|
17
|
+
ContextWindowManager,
|
|
18
|
+
ContextWindowResult,
|
|
19
|
+
} from "../../../context/window-manager.js";
|
|
20
|
+
import type { Message } from "../../../providers/types.js";
|
|
21
|
+
import {
|
|
22
|
+
type CompactionArgs,
|
|
23
|
+
type CompactionResult,
|
|
24
|
+
PluginExecutionError,
|
|
25
|
+
type TurnContext,
|
|
26
|
+
} from "../../types.js";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Name under which the default plugin registers. Exposed so tests and later
|
|
30
|
+
* plugins can assert registration order or override the default via
|
|
31
|
+
* composition.
|
|
32
|
+
*/
|
|
33
|
+
export const DEFAULT_COMPACTION_PLUGIN_NAME = "default-compaction";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Read `contextWindowManager` off the turn context. Throws
|
|
37
|
+
* {@link PluginExecutionError} when absent so the failure attributes cleanly
|
|
38
|
+
* to the default plugin instead of manifesting as a later NPE.
|
|
39
|
+
*/
|
|
40
|
+
function extractManager(ctx: TurnContext): ContextWindowManager {
|
|
41
|
+
const manager = ctx.contextWindowManager;
|
|
42
|
+
if (
|
|
43
|
+
manager == null ||
|
|
44
|
+
typeof manager !== "object" ||
|
|
45
|
+
typeof (manager as { maybeCompact?: unknown }).maybeCompact !== "function"
|
|
46
|
+
) {
|
|
47
|
+
throw new PluginExecutionError(
|
|
48
|
+
"default-compaction: ctx.contextWindowManager is missing — orchestrator must attach it before invoking compaction",
|
|
49
|
+
DEFAULT_COMPACTION_PLUGIN_NAME,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return manager;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Run compaction for the turn: reads the context window manager off the turn
|
|
57
|
+
* context and returns the (possibly summarized) message history from
|
|
58
|
+
* `maybeCompact`.
|
|
59
|
+
*/
|
|
60
|
+
export async function defaultCompactionTerminal(
|
|
61
|
+
args: CompactionArgs,
|
|
62
|
+
ctx: TurnContext,
|
|
63
|
+
): Promise<CompactionResult> {
|
|
64
|
+
const manager = extractManager(ctx);
|
|
65
|
+
const messages = args.messages as Message[];
|
|
66
|
+
const options = args.options as ContextWindowCompactOptions | undefined;
|
|
67
|
+
const result: ContextWindowResult = await manager.maybeCompact(
|
|
68
|
+
messages,
|
|
69
|
+
args.signal,
|
|
70
|
+
options,
|
|
71
|
+
);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
@@ -25,10 +25,11 @@
|
|
|
25
25
|
|
|
26
26
|
import { registerPlugin, resetPluginRegistryForTests } from "../registry.js";
|
|
27
27
|
import { type Plugin, PluginExecutionError } from "../types.js";
|
|
28
|
+
import { defaultCircuitBreakerPlugin } from "./circuit-breaker/register.js";
|
|
28
29
|
import { defaultCompactionPlugin } from "./compaction/register.js";
|
|
29
30
|
import { defaultEmptyResponsePlugin } from "./empty-response/register.js";
|
|
30
31
|
import { defaultHistoryRepairPlugin } from "./history-repair/register.js";
|
|
31
|
-
import {
|
|
32
|
+
import { defaultOverflowReducePlugin } from "./overflow-reduce/register.js";
|
|
32
33
|
import { defaultTitleGeneratePlugin } from "./title-generate/register.js";
|
|
33
34
|
import { defaultToolErrorPlugin } from "./tool-error/register.js";
|
|
34
35
|
import { defaultToolResultTruncatePlugin } from "./tool-result-truncate/register.js";
|
|
@@ -48,10 +49,11 @@ function getAllDefaultPlugins(): readonly Plugin[] {
|
|
|
48
49
|
defaultToolResultTruncatePlugin,
|
|
49
50
|
defaultEmptyResponsePlugin,
|
|
50
51
|
defaultToolErrorPlugin,
|
|
52
|
+
defaultOverflowReducePlugin,
|
|
51
53
|
defaultHistoryRepairPlugin,
|
|
52
54
|
defaultCompactionPlugin,
|
|
55
|
+
defaultCircuitBreakerPlugin,
|
|
53
56
|
defaultTitleGeneratePlugin,
|
|
54
|
-
memoryV3ShadowPlugin,
|
|
55
57
|
];
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -83,7 +85,7 @@ export function registerDefaultPlugins(): void {
|
|
|
83
85
|
* so integration tests that exercise the full agent loop have a
|
|
84
86
|
* production-parity plugin stack. Use this in `beforeEach` of tests that
|
|
85
87
|
* dispatch through pipelines with a terminal that assumes the default
|
|
86
|
-
* plugin handles every op (e.g.
|
|
88
|
+
* plugin handles every op (e.g. overflowReduce).
|
|
87
89
|
*
|
|
88
90
|
* Tests that specifically need an empty registry (pipeline-unit tests, the
|
|
89
91
|
* plugin-registry tests themselves) should continue to call
|