@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
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import * as appStore from "../../../../memory/app-store.js";
|
|
2
|
-
import type {
|
|
3
|
-
ToolContext,
|
|
4
|
-
ToolExecutionResult,
|
|
5
|
-
} from "../../../../tools/types.js";
|
|
6
|
-
|
|
7
|
-
interface AppListEntry {
|
|
8
|
-
app_id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
description?: string;
|
|
11
|
-
updated_at: number;
|
|
12
|
-
created_at: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function toEntry(app: appStore.AppDefinition): AppListEntry {
|
|
16
|
-
return {
|
|
17
|
-
app_id: app.id,
|
|
18
|
-
name: app.name,
|
|
19
|
-
...(app.description ? { description: app.description } : {}),
|
|
20
|
-
updated_at: app.updatedAt,
|
|
21
|
-
created_at: app.createdAt,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function run(
|
|
26
|
-
input: Record<string, unknown>,
|
|
27
|
-
_context: ToolContext,
|
|
28
|
-
): Promise<ToolExecutionResult> {
|
|
29
|
-
const apps = appStore.listApps();
|
|
30
|
-
const entries = apps.map(toEntry);
|
|
31
|
-
|
|
32
|
-
const query =
|
|
33
|
-
typeof input.query === "string" ? input.query.trim().toLowerCase() : "";
|
|
34
|
-
|
|
35
|
-
if (!query) {
|
|
36
|
-
return {
|
|
37
|
-
content: JSON.stringify({ count: entries.length, apps: entries }),
|
|
38
|
-
isError: false,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Resolve the app the user mentioned by name. Prefer an exact (case-insensitive)
|
|
43
|
-
// name match, then fall back to substring matches in either direction so
|
|
44
|
-
// "habit tracker" resolves "Habit Tracker" and "my budget" resolves "Budget".
|
|
45
|
-
const exact = entries.filter((e) => e.name.toLowerCase() === query);
|
|
46
|
-
const matches =
|
|
47
|
-
exact.length > 0
|
|
48
|
-
? exact
|
|
49
|
-
: entries.filter((e) => {
|
|
50
|
-
const name = e.name.toLowerCase();
|
|
51
|
-
return name.includes(query) || query.includes(name);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
content: JSON.stringify({
|
|
56
|
-
query: input.query,
|
|
57
|
-
match_count: matches.length,
|
|
58
|
-
matches,
|
|
59
|
-
}),
|
|
60
|
-
isError: false,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-memory registry of active {@link Conversation} instances, keyed by
|
|
3
|
-
* conversation ID, plus the read/write accessors over it.
|
|
4
|
-
*
|
|
5
|
-
* This is a leaf module: it imports `Conversation` as a type only, so any
|
|
6
|
-
* layer — including the memory-retrieval plugin's injectors, which only know a
|
|
7
|
-
* conversation id — can look up the live conversation and read its state
|
|
8
|
-
* without pulling in the daemon-core creation graph (providers, system-prompt
|
|
9
|
-
* assembly, the `Conversation` class value) that `getOrCreateConversation` in
|
|
10
|
-
* `conversation-store` depends on. Keeping the registry free of those value
|
|
11
|
-
* imports is what lets the injector chain consume it without forming an import
|
|
12
|
-
* cycle (`injectors → store → conversation → agent-loop → runtime-assembly →
|
|
13
|
-
* injector-chain → injectors`).
|
|
14
|
-
*
|
|
15
|
-
* `conversation-store` owns the creation/reuse lifecycle and writes top-level
|
|
16
|
-
* conversations into this map via {@link setConversation}.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import type { Conversation } from "./conversation.js";
|
|
20
|
-
|
|
21
|
-
const conversations = new Map<string, Conversation>();
|
|
22
|
-
|
|
23
|
-
// ── Read helpers ───────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
export function findConversation(
|
|
26
|
-
conversationId: string | undefined,
|
|
27
|
-
): Conversation | undefined {
|
|
28
|
-
if (!conversationId) return undefined;
|
|
29
|
-
return conversations.get(conversationId);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function findConversationBySurfaceId(
|
|
33
|
-
surfaceId: string,
|
|
34
|
-
): Conversation | undefined {
|
|
35
|
-
// Fast path: exact surfaceId match in surfaceState
|
|
36
|
-
for (const c of conversations.values()) {
|
|
37
|
-
if (c.surfaceState.has(surfaceId)) return c;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Fallback: standalone app surfaces use "app-open-{appId}" IDs that
|
|
41
|
-
// were never part of any conversation. Extract the appId and find
|
|
42
|
-
// a conversation whose surfaceState has a surface for that app.
|
|
43
|
-
const appOpenPrefix = "app-open-";
|
|
44
|
-
if (surfaceId.startsWith(appOpenPrefix)) {
|
|
45
|
-
const appId = surfaceId.slice(appOpenPrefix.length);
|
|
46
|
-
for (const c of conversations.values()) {
|
|
47
|
-
for (const [, state] of c.surfaceState.entries()) {
|
|
48
|
-
const data = state.data as unknown as Record<string, unknown>;
|
|
49
|
-
if (data?.appId === appId) {
|
|
50
|
-
// Register this surfaceId so subsequent lookups are O(1)
|
|
51
|
-
c.surfaceState.set(surfaceId, state);
|
|
52
|
-
return c;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function conversationCount(): number {
|
|
62
|
-
return conversations.size;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Iterate over all active conversations. */
|
|
66
|
-
export function allConversations(): IterableIterator<Conversation> {
|
|
67
|
-
return conversations.values();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Iterate over all [id, conversation] entries. */
|
|
71
|
-
export function conversationEntries(): IterableIterator<
|
|
72
|
-
[string, Conversation]
|
|
73
|
-
> {
|
|
74
|
-
return conversations.entries();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Iterate over all active conversation IDs. */
|
|
78
|
-
export function conversationIds(): IterableIterator<string> {
|
|
79
|
-
return conversations.keys();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ── Write helpers ──────────────────────────────────────────────────
|
|
83
|
-
|
|
84
|
-
export function setConversation(
|
|
85
|
-
conversationId: string,
|
|
86
|
-
conversation: Conversation,
|
|
87
|
-
): void {
|
|
88
|
-
conversations.set(conversationId, conversation);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function deleteConversation(conversationId: string): boolean {
|
|
92
|
-
return conversations.delete(conversationId);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function clearConversations(): void {
|
|
96
|
-
conversations.clear();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ── Underlying Map (for the evictor, which takes a mutable ref) ───
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Expose the raw Map for the {@link ConversationEvictor}, which needs
|
|
103
|
-
* a mutable reference to delete entries during sweeps. No other code
|
|
104
|
-
* should use this — prefer the named helpers above.
|
|
105
|
-
*/
|
|
106
|
-
export function getConversationMap(): Map<string, Conversation> {
|
|
107
|
-
return conversations;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ── Subagent live-conversation index ───────────────────────────────
|
|
111
|
-
//
|
|
112
|
-
// Subagents run their own agent loop — and therefore the injector chain — but
|
|
113
|
-
// are owned by the `SubagentManager` rather than the daemon's eviction-managed
|
|
114
|
-
// store, so they are deliberately absent from `conversations` above. This
|
|
115
|
-
// point-lookup index lets the per-conversation injectors (workspace context,
|
|
116
|
-
// disk-pressure warning) resolve a subagent's live `Conversation` by id and
|
|
117
|
-
// read state off it. It is intentionally excluded from the iteration accessors
|
|
118
|
-
// and the evictor map so subagent lifecycle stays solely with the manager.
|
|
119
|
-
|
|
120
|
-
const subagentConversations = new Map<string, Conversation>();
|
|
121
|
-
|
|
122
|
-
/** Register a subagent's live conversation for point lookups. */
|
|
123
|
-
export function setSubagentConversation(
|
|
124
|
-
conversationId: string,
|
|
125
|
-
conversation: Conversation,
|
|
126
|
-
): void {
|
|
127
|
-
subagentConversations.set(conversationId, conversation);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Remove a subagent's conversation from the index. Guards against clobbering a
|
|
132
|
-
* newer registration for the same id by only deleting when the stored entry
|
|
133
|
-
* still points at this instance.
|
|
134
|
-
*/
|
|
135
|
-
export function removeSubagentConversation(
|
|
136
|
-
conversationId: string,
|
|
137
|
-
conversation: Conversation,
|
|
138
|
-
): void {
|
|
139
|
-
if (subagentConversations.get(conversationId) === conversation) {
|
|
140
|
-
subagentConversations.delete(conversationId);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Resolve a live `Conversation` by id, including subagent conversations.
|
|
146
|
-
* Top-level conversations are checked first, then subagents. Used by the
|
|
147
|
-
* per-conversation injectors, which run for subagent turns too; other callers
|
|
148
|
-
* should use {@link findConversation}, which is scoped to the eviction-managed
|
|
149
|
-
* top-level conversations.
|
|
150
|
-
*/
|
|
151
|
-
export function findConversationOrSubagent(
|
|
152
|
-
conversationId: string | undefined,
|
|
153
|
-
): Conversation | undefined {
|
|
154
|
-
if (!conversationId) return undefined;
|
|
155
|
-
return (
|
|
156
|
-
conversations.get(conversationId) ??
|
|
157
|
-
subagentConversations.get(conversationId)
|
|
158
|
-
);
|
|
159
|
-
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import type { ContextWindowConfig } from "../config/schemas/inference.js";
|
|
2
|
-
import type {
|
|
3
|
-
ContextWindowCompactOptions,
|
|
4
|
-
ContextWindowResult,
|
|
5
|
-
} from "../context/window-manager.js";
|
|
6
|
-
import type { Message } from "../providers/types.js";
|
|
7
|
-
import {
|
|
8
|
-
createInitialReducerState,
|
|
9
|
-
reduceContextOverflow,
|
|
10
|
-
type ReducerState,
|
|
11
|
-
} from "./context-overflow-reducer.js";
|
|
12
|
-
import type { InjectionMode } from "./conversation-runtime-assembly.js";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Input to the overflow-reduction loop. Captures everything the reducer
|
|
16
|
-
* tier loop needs, including the message history, reducer configuration,
|
|
17
|
-
* and side-effect callbacks that bridge the loop back to the orchestrator's
|
|
18
|
-
* mutable per-turn state (context-window manager, activity emitter, runtime
|
|
19
|
-
* injection reassembly, memory reinjection).
|
|
20
|
-
*
|
|
21
|
-
* The callbacks are supplied by the orchestrator because the reducer loop
|
|
22
|
-
* needs to coordinate with state that lives on the `AgentLoopConversationContext`
|
|
23
|
-
* (message mutation, compaction event emission, circuit breaker tracking,
|
|
24
|
-
* injection block reassembly). Keeping them as explicit callbacks keeps the
|
|
25
|
-
* loop free of any dependency on the agent-loop context object.
|
|
26
|
-
*/
|
|
27
|
-
export interface OverflowReduceArgs {
|
|
28
|
-
/** Bare persisted message history (the reducer applies results to a copy
|
|
29
|
-
* of this array). */
|
|
30
|
-
readonly messages: Message[];
|
|
31
|
-
/** Current run-time message array with runtime injections applied. */
|
|
32
|
-
readonly runMessages: Message[];
|
|
33
|
-
/** System prompt used for post-step token estimation. */
|
|
34
|
-
readonly systemPrompt: string;
|
|
35
|
-
/** Provider name used for token estimation (calibration provider key). */
|
|
36
|
-
readonly providerName: string;
|
|
37
|
-
/** Context window config (drives compaction behavior). */
|
|
38
|
-
readonly contextWindow: ContextWindowConfig;
|
|
39
|
-
/** Token budget the reducer must get below (preflight budget). */
|
|
40
|
-
readonly preflightBudget: number;
|
|
41
|
-
/** Tool-token overhead included in every estimation call. */
|
|
42
|
-
readonly toolTokenBudget?: number;
|
|
43
|
-
/** Maximum reducer iterations before the loop exits unconditionally. */
|
|
44
|
-
readonly maxAttempts: number;
|
|
45
|
-
/** Abort signal threaded through compaction calls. */
|
|
46
|
-
readonly abortSignal?: AbortSignal;
|
|
47
|
-
/**
|
|
48
|
-
* Compaction callback — the loop never owns the ContextWindowManager
|
|
49
|
-
* instance. The orchestrator supplies this closure so the loop can
|
|
50
|
-
* delegate the forced-compaction tier without crossing the infra
|
|
51
|
-
* boundary on its own.
|
|
52
|
-
*/
|
|
53
|
-
readonly compactFn: (
|
|
54
|
-
messages: Message[],
|
|
55
|
-
signal: AbortSignal | undefined,
|
|
56
|
-
options: unknown,
|
|
57
|
-
) => Promise<ContextWindowResult>;
|
|
58
|
-
/**
|
|
59
|
-
* Invoked before each reducer iteration to emit the `context_compacting`
|
|
60
|
-
* activity state. The orchestrator owns activity emission because the
|
|
61
|
-
* signal is trust/channel aware.
|
|
62
|
-
*/
|
|
63
|
-
readonly emitActivityState: () => void;
|
|
64
|
-
/**
|
|
65
|
-
* Invoked after each reducer step that produced a successful compaction.
|
|
66
|
-
* Handles circuit-breaker tracking, event emission, and context mutation.
|
|
67
|
-
*/
|
|
68
|
-
readonly onCompactionResult: (
|
|
69
|
-
result: ContextWindowResult,
|
|
70
|
-
compactedBasis?: Message[],
|
|
71
|
-
) => void | Promise<void>;
|
|
72
|
-
/**
|
|
73
|
-
* Invoked after each step to rebuild `runMessages` from the step's
|
|
74
|
-
* reduced history with the requested injection mode. The orchestrator
|
|
75
|
-
* owns this helper so the full per-turn injection options object doesn't
|
|
76
|
-
* leak into the loop. The current reduced messages array is passed
|
|
77
|
-
* explicitly so the orchestrator doesn't need to read mutable shared
|
|
78
|
-
* state. Returns the new `runMessages`.
|
|
79
|
-
*
|
|
80
|
-
* Two distinct "did compact" signals are passed so the orchestrator can
|
|
81
|
-
* apply the correct per-iteration vs sticky gating:
|
|
82
|
-
* - `stepCompacted` — whether THIS iteration's reducer step produced a
|
|
83
|
-
* fresh compaction. Gates PKB / NOW re-injection: compaction strips the
|
|
84
|
-
* existing blocks, so only iterations that just compacted need the
|
|
85
|
-
* content re-threaded. Iterations that only truncated tool results or
|
|
86
|
-
* downgraded injections must NOT force a re-injection or the token
|
|
87
|
-
* count grows each round.
|
|
88
|
-
* - `accumulatedCompacted` — whether ANY iteration in this invocation has
|
|
89
|
-
* compacted. Gates `slackChronologicalMessages` suppression: once
|
|
90
|
-
* compaction has run, the captured Slack transcript snapshot would
|
|
91
|
-
* overwrite the compacted history, so it must stay suppressed for every
|
|
92
|
-
* subsequent iteration even if that iteration didn't re-compact.
|
|
93
|
-
*/
|
|
94
|
-
readonly reinjectForMode: (
|
|
95
|
-
messages: Message[],
|
|
96
|
-
mode: InjectionMode,
|
|
97
|
-
stepCompacted: boolean,
|
|
98
|
-
accumulatedCompacted: boolean,
|
|
99
|
-
) => Promise<Message[]>;
|
|
100
|
-
/**
|
|
101
|
-
* Invoked after each step to post-estimate the rebuilt `runMessages`.
|
|
102
|
-
* Pulled out so the orchestrator controls how estimation is performed
|
|
103
|
-
* (and which fields feed it) without the loop reimplementing it.
|
|
104
|
-
*/
|
|
105
|
-
readonly estimatePostInjection: (runMessages: Message[]) => number;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** Output of the overflow-reduction loop. */
|
|
109
|
-
export interface OverflowReduceResult {
|
|
110
|
-
/** Final reduced `ctx.messages` value. */
|
|
111
|
-
readonly messages: Message[];
|
|
112
|
-
/** Final `runMessages` with re-applied runtime injections. */
|
|
113
|
-
readonly runMessages: Message[];
|
|
114
|
-
/** Final injection mode (may be `"minimal"` if the downgrade tier fired). */
|
|
115
|
-
readonly injectionMode: InjectionMode;
|
|
116
|
-
/** Accumulated reducer state at exit. */
|
|
117
|
-
readonly reducerState: ReducerState;
|
|
118
|
-
/** True if any step successfully compacted history. */
|
|
119
|
-
readonly reducerCompacted: boolean;
|
|
120
|
-
/** How many iterations of the tier loop executed. */
|
|
121
|
-
readonly attempts: number;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Run the context-overflow reducer tier loop — forced compaction, tool-result
|
|
126
|
-
* truncation, media stubbing, injection downgrade — plus the post-step
|
|
127
|
-
* re-injection / re-estimation convergence check.
|
|
128
|
-
*
|
|
129
|
-
* The forced-compaction tier is delegated through `args.compactFn`; the other
|
|
130
|
-
* tiers mutate the message array directly. After each step the orchestrator
|
|
131
|
-
* rebuilds `runMessages` via `args.reinjectForMode` and the loop re-estimates
|
|
132
|
-
* the post-injection token count, exiting once it fits the preflight budget,
|
|
133
|
-
* the reducer is exhausted, or `maxAttempts` is reached.
|
|
134
|
-
*/
|
|
135
|
-
export async function runOverflowReductionLoop(
|
|
136
|
-
args: OverflowReduceArgs,
|
|
137
|
-
): Promise<OverflowReduceResult> {
|
|
138
|
-
let messages = args.messages;
|
|
139
|
-
let runMessages = args.runMessages;
|
|
140
|
-
let injectionMode: "full" | "minimal" = "full";
|
|
141
|
-
let reducerState: ReducerState = createInitialReducerState();
|
|
142
|
-
let reducerCompacted = false;
|
|
143
|
-
let attempts = 0;
|
|
144
|
-
|
|
145
|
-
while (attempts < args.maxAttempts && !reducerState.exhausted) {
|
|
146
|
-
// Abort check at the top of every iteration. When the caller aborts
|
|
147
|
-
// externally, this check lets us bail out BETWEEN iterations rather
|
|
148
|
-
// than letting another round of compaction / re-injection mutate
|
|
149
|
-
// `ctx.messages` after the turn has already failed. Individual
|
|
150
|
-
// `reduceContextOverflow` calls also honor the signal, but without this
|
|
151
|
-
// gate a fresh iteration could still start after the signal fires,
|
|
152
|
-
// since the previous one returned normally before the abort propagated.
|
|
153
|
-
args.abortSignal?.throwIfAborted();
|
|
154
|
-
|
|
155
|
-
attempts++;
|
|
156
|
-
args.emitActivityState();
|
|
157
|
-
|
|
158
|
-
const basisMessages = messages;
|
|
159
|
-
const step = await reduceContextOverflow(
|
|
160
|
-
basisMessages,
|
|
161
|
-
{
|
|
162
|
-
providerName: args.providerName,
|
|
163
|
-
systemPrompt: args.systemPrompt,
|
|
164
|
-
contextWindow: args.contextWindow,
|
|
165
|
-
targetTokens: args.preflightBudget,
|
|
166
|
-
toolTokenBudget: args.toolTokenBudget,
|
|
167
|
-
},
|
|
168
|
-
reducerState,
|
|
169
|
-
(msgs, signal, opts: ContextWindowCompactOptions) =>
|
|
170
|
-
args.compactFn(msgs, signal, opts),
|
|
171
|
-
args.abortSignal,
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
reducerState = step.state;
|
|
175
|
-
messages = step.messages;
|
|
176
|
-
injectionMode = step.state.injectionMode;
|
|
177
|
-
|
|
178
|
-
// Per-iteration compaction flag: whether THIS step just produced a
|
|
179
|
-
// fresh compaction. PKB / NOW re-injection is gated on this — see the
|
|
180
|
-
// reinjectForMode JSDoc for why the two signals differ.
|
|
181
|
-
const stepCompacted = step.compactionResult?.compacted === true;
|
|
182
|
-
|
|
183
|
-
// Let the orchestrator apply compaction side effects (circuit-breaker
|
|
184
|
-
// tracking, event emission, ctx mutation) before we re-inject.
|
|
185
|
-
if (step.compactionResult) {
|
|
186
|
-
await args.onCompactionResult(step.compactionResult, basisMessages);
|
|
187
|
-
if (stepCompacted) {
|
|
188
|
-
reducerCompacted = true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Second abort gate — if the side effects or the step itself took us
|
|
193
|
-
// past the deadline, don't rebuild runMessages or iterate again.
|
|
194
|
-
args.abortSignal?.throwIfAborted();
|
|
195
|
-
|
|
196
|
-
// Rebuild runMessages via the orchestrator-supplied helper (which
|
|
197
|
-
// re-runs `applyRuntimeInjections` with potentially downgraded mode
|
|
198
|
-
// and freshly re-hydrated PKB/NOW blocks after compaction). We pass
|
|
199
|
-
// the current reduced `messages` explicitly so the orchestrator never
|
|
200
|
-
// has to read from mutable shared state to rebuild runMessages — a
|
|
201
|
-
// tier that doesn't trigger compaction (tool-result truncation, media
|
|
202
|
-
// stubbing) won't update `ctx.messages` on its own.
|
|
203
|
-
//
|
|
204
|
-
// `stepCompacted` and `reducerCompacted` are both passed so the
|
|
205
|
-
// orchestrator can gate PKB / NOW re-injection per-iteration while
|
|
206
|
-
// keeping `slackChronologicalMessages` suppressed once any iteration
|
|
207
|
-
// has compacted.
|
|
208
|
-
runMessages = await args.reinjectForMode(
|
|
209
|
-
messages,
|
|
210
|
-
injectionMode,
|
|
211
|
-
stepCompacted,
|
|
212
|
-
reducerCompacted,
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
// Re-estimate with injections included — `step.estimatedTokens` was
|
|
216
|
-
// computed on bare history and doesn't account for tokens added by
|
|
217
|
-
// runtime injections.
|
|
218
|
-
const postInjectionTokens = args.estimatePostInjection(runMessages);
|
|
219
|
-
if (postInjectionTokens <= args.preflightBudget) break;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return {
|
|
223
|
-
messages,
|
|
224
|
-
runMessages,
|
|
225
|
-
injectionMode,
|
|
226
|
-
reducerState,
|
|
227
|
-
reducerCompacted,
|
|
228
|
-
attempts,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
-
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
-
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
-
|
|
5
|
-
const CHECKPOINT_KEY = "migration_acp_session_history_cwd_v1";
|
|
6
|
-
|
|
7
|
-
const TABLE = "acp_session_history";
|
|
8
|
-
const COLUMN = "cwd";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Add a nullable `cwd TEXT` column to `acp_session_history`.
|
|
12
|
-
*
|
|
13
|
-
* Records the working directory the ACP agent process was spawned with so
|
|
14
|
-
* that a persisted session can later be resumed (`session/load` /
|
|
15
|
-
* `session/resume` both require the original cwd to reconstruct params).
|
|
16
|
-
*
|
|
17
|
-
* `NULL` for rows persisted before this migration ran — legacy sessions
|
|
18
|
-
* simply are not resumable.
|
|
19
|
-
*
|
|
20
|
-
* Idempotent — the PRAGMA guard makes re-running a no-op once the column
|
|
21
|
-
* exists.
|
|
22
|
-
*/
|
|
23
|
-
export function migrateAcpSessionHistoryCwd(database: DrizzleDb): void {
|
|
24
|
-
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
25
|
-
const raw = getSqliteFrom(database);
|
|
26
|
-
|
|
27
|
-
const columns = raw.query(`PRAGMA table_info(${TABLE})`).all() as Array<{
|
|
28
|
-
name: string;
|
|
29
|
-
}>;
|
|
30
|
-
const columnNames = new Set(columns.map((c) => c.name));
|
|
31
|
-
|
|
32
|
-
if (!columnNames.has(COLUMN)) {
|
|
33
|
-
raw.exec(`ALTER TABLE ${TABLE} ADD COLUMN ${COLUMN} TEXT`);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default compaction implementation.
|
|
3
|
-
*
|
|
4
|
-
* Summarizes conversation history when the context window fills up by
|
|
5
|
-
* delegating to a {@link ContextWindowManager}. The agent loop calls
|
|
6
|
-
* {@link defaultCompact} directly with a {@link CompactionContext}; the request
|
|
7
|
-
* carries the conversational inputs while the manager performs the work.
|
|
8
|
-
*
|
|
9
|
-
* This module is side-effect free: importing it does not register any plugin.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type {
|
|
13
|
-
ContextWindowManager,
|
|
14
|
-
ContextWindowResult,
|
|
15
|
-
} from "../../../context/window-manager.js";
|
|
16
|
-
import type { Message } from "../../../providers/types.js";
|
|
17
|
-
import type { TrustClass } from "../../../runtime/actor-trust-resolver.js";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Name under which the default compaction plugin registers. Exposed so call
|
|
21
|
-
* sites can attribute compaction failures to the default plugin.
|
|
22
|
-
*/
|
|
23
|
-
export const DEFAULT_COMPACTION_PLUGIN_NAME = "default-compaction";
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Self-describing compaction request handed to {@link defaultCompact}. Carries
|
|
27
|
-
* the conversational inputs plus the {@link ContextWindowManager} that runs the
|
|
28
|
-
* summary, so the request is the part that can grow toward a model-facing
|
|
29
|
-
* compaction-method shape without coupling callers to the manager's option bag.
|
|
30
|
-
*/
|
|
31
|
-
export interface CompactionContext {
|
|
32
|
-
/** Context window manager that performs the compaction. */
|
|
33
|
-
manager: ContextWindowManager;
|
|
34
|
-
/** Message history to consider for compaction. */
|
|
35
|
-
messages: Message[];
|
|
36
|
-
/** Abort signal forwarded to the compaction summary call. */
|
|
37
|
-
signal?: AbortSignal;
|
|
38
|
-
/** Skip the auto-threshold check (forced/overflow/emergency compaction). */
|
|
39
|
-
force?: boolean;
|
|
40
|
-
/** Per-conversation inference-profile override for the summary call. */
|
|
41
|
-
overrideProfile?: string | null;
|
|
42
|
-
/** Pre-computed token estimate from a prior `shouldCompact()` call. */
|
|
43
|
-
precomputedEstimate?: number;
|
|
44
|
-
/** Legacy keep-boundary hint forwarded to the compactor. */
|
|
45
|
-
minKeepRecentUserTurns?: number;
|
|
46
|
-
/** Trust class of the actor whose turn triggered compaction. */
|
|
47
|
-
actorTrustClass?: TrustClass;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Run compaction for the turn: delegates to the request's context window
|
|
52
|
-
* manager and returns the (possibly summarized) message history.
|
|
53
|
-
*/
|
|
54
|
-
export async function defaultCompact(
|
|
55
|
-
context: CompactionContext,
|
|
56
|
-
): Promise<ContextWindowResult> {
|
|
57
|
-
const { manager, messages, signal, ...options } = context;
|
|
58
|
-
return manager.maybeCompact(messages, signal, options);
|
|
59
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* No-op `post-compact` scaffolding for the memory-v3-shadow plugin.
|
|
3
|
-
*
|
|
4
|
-
* v3 re-injection after mid-turn compaction is not yet owned by this plugin —
|
|
5
|
-
* the active injector still runs through the static chain. Once the
|
|
6
|
-
* post-compaction hook API stabilizes we will import `memoryV3Injector` from
|
|
7
|
-
* `../injector.js` and re-apply it here. Until then this hook does nothing.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { PluginHookFn } from "@vellumai/plugin-api";
|
|
11
|
-
|
|
12
|
-
const postCompact: PluginHookFn = async () => {};
|
|
13
|
-
|
|
14
|
-
export default postCompact;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* No-op `user-prompt-submit` scaffolding for the memory-v3-shadow plugin.
|
|
3
|
-
*
|
|
4
|
-
* The v3 injector currently runs through the static injector chain
|
|
5
|
-
* (`memory-retrieval/injector-chain.ts`), not through this hook. Once the
|
|
6
|
-
* prompt-submit hook API stabilizes we will import `memoryV3Injector` from
|
|
7
|
-
* `../injector.js` and run it here, so v3 injection is owned by the plugin's
|
|
8
|
-
* own lifecycle rather than the loop-driven chain. Until then this hook
|
|
9
|
-
* intentionally does nothing.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type {
|
|
13
|
-
PluginHookFn,
|
|
14
|
-
UserPromptSubmitContext,
|
|
15
|
-
} from "@vellumai/plugin-api";
|
|
16
|
-
|
|
17
|
-
const userPromptSubmit: PluginHookFn<UserPromptSubmitContext> = async () => {};
|
|
18
|
-
|
|
19
|
-
export default userPromptSubmit;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The memory-v3 {@link Injector}. Reads both v3 flags:
|
|
3
|
-
* - `memory-v3-live` on → orchestrate, log, render the working-set selection
|
|
4
|
-
* into a `<memory>` block, and return it at v2's dynamic-memory placement.
|
|
5
|
-
* - `memory-v3-shadow` on (live off) → orchestrate + log only, return `null`.
|
|
6
|
-
* - both off → return `null` (no orchestration).
|
|
7
|
-
*
|
|
8
|
-
* Empty selection and any failure return `null` (no v3 injection). v2
|
|
9
|
-
* suppression keys off BOTH the flag AND this return value, so a `null` here
|
|
10
|
-
* (failure or empty selection) falls back to v2 memory rather than dropping all
|
|
11
|
-
* memory.
|
|
12
|
-
*
|
|
13
|
-
* Orchestration and telemetry live in {@link observeTurn}; this module is the
|
|
14
|
-
* thin injector wrapper that renders the result for live injection.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
|
|
18
|
-
import { getConfig } from "../../../config/loader.js";
|
|
19
|
-
import { getLogger } from "../../../util/logger.js";
|
|
20
|
-
import {
|
|
21
|
-
type InjectionBlock,
|
|
22
|
-
type Injector,
|
|
23
|
-
type TurnContext as PluginTurnContext,
|
|
24
|
-
} from "../../types.js";
|
|
25
|
-
import { renderV3PageContent } from "./page-content.js";
|
|
26
|
-
import { renderMemoryBlock } from "./render-injection.js";
|
|
27
|
-
import {
|
|
28
|
-
MEMORY_V3_LIVE,
|
|
29
|
-
MEMORY_V3_SHADOW,
|
|
30
|
-
observeTurn,
|
|
31
|
-
} from "./shadow-plugin.js";
|
|
32
|
-
import { MEMORY_V3_BLOCK_ID } from "./types.js";
|
|
33
|
-
|
|
34
|
-
const log = getLogger("memory-v3-shadow");
|
|
35
|
-
|
|
36
|
-
export const memoryV3Injector: Injector = {
|
|
37
|
-
name: "memory-v3-shadow",
|
|
38
|
-
// High order so it sorts last; the live `<memory>` block uses the
|
|
39
|
-
// after-memory-prefix placement so it lands at the memory boundary regardless
|
|
40
|
-
// of this sort key, which only orders content-producing injectors.
|
|
41
|
-
order: 1000,
|
|
42
|
-
async produce(ctx: PluginTurnContext): Promise<InjectionBlock | null> {
|
|
43
|
-
const config = getConfig();
|
|
44
|
-
const live = isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config);
|
|
45
|
-
const shadow = isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config);
|
|
46
|
-
if (!live && !shadow) return null;
|
|
47
|
-
|
|
48
|
-
const result = await observeTurn(ctx.conversationId, ctx.turnIndex);
|
|
49
|
-
if (!live || !result) return null;
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
// `renderMemoryBlock` returns "" for an empty selection; inject nothing.
|
|
53
|
-
const text = await renderMemoryBlock(
|
|
54
|
-
result.finalInjection,
|
|
55
|
-
renderV3PageContent,
|
|
56
|
-
);
|
|
57
|
-
if (text.length === 0) return null;
|
|
58
|
-
return {
|
|
59
|
-
id: MEMORY_V3_BLOCK_ID,
|
|
60
|
-
text,
|
|
61
|
-
// Mirror v2's dynamic `<memory>` block placement.
|
|
62
|
-
placement: "after-memory-prefix",
|
|
63
|
-
};
|
|
64
|
-
} catch (err) {
|
|
65
|
-
log.warn(
|
|
66
|
-
{
|
|
67
|
-
err: err instanceof Error ? err.message : String(err),
|
|
68
|
-
conversationId: ctx.conversationId,
|
|
69
|
-
},
|
|
70
|
-
"memory-v3 live render failed (non-fatal) — falling back to v2",
|
|
71
|
-
);
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default `memory-v3-shadow` plugin.
|
|
3
|
-
*
|
|
4
|
-
* Houses the memory-v3 shadow/live orchestration engine (this directory) and
|
|
5
|
-
* its injector (`./injector.ts`). The injector is still consumed by the static
|
|
6
|
-
* chain in `memory-retrieval/injector-chain.ts`; the `user-prompt-submit` /
|
|
7
|
-
* `post-compact` hooks below are no-op scaffolding for the eventual
|
|
8
|
-
* convergence, when v3 injection moves off the loop-driven chain and into these
|
|
9
|
-
* lifecycle hooks. See each hook file for the convergence note.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { type Plugin } from "../../types.js";
|
|
13
|
-
import postCompact from "./hooks/post-compact.js";
|
|
14
|
-
import userPromptSubmit from "./hooks/user-prompt-submit.js";
|
|
15
|
-
import pkg from "./package.json" with { type: "json" };
|
|
16
|
-
|
|
17
|
-
export const memoryV3ShadowPlugin: Plugin = {
|
|
18
|
-
manifest: {
|
|
19
|
-
name: pkg.name,
|
|
20
|
-
version: pkg.version,
|
|
21
|
-
},
|
|
22
|
-
hooks: {
|
|
23
|
-
"user-prompt-submit": userPromptSubmit,
|
|
24
|
-
"post-compact": postCompact,
|
|
25
|
-
},
|
|
26
|
-
};
|