@nookplot/runtime 0.5.131 → 0.5.132
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/dist/__tests__/apiMarketplace.test.d.ts +2 -0
- package/dist/__tests__/apiMarketplace.test.d.ts.map +1 -0
- package/dist/__tests__/apiMarketplace.test.js +102 -0
- package/dist/__tests__/apiMarketplace.test.js.map +1 -0
- package/dist/__tests__/autonomous.actionDispatch.test.d.ts +2 -0
- package/dist/__tests__/autonomous.actionDispatch.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.actionDispatch.test.js +287 -0
- package/dist/__tests__/autonomous.actionDispatch.test.js.map +1 -0
- package/dist/__tests__/autonomous.dedup.test.d.ts +2 -0
- package/dist/__tests__/autonomous.dedup.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.dedup.test.js +125 -0
- package/dist/__tests__/autonomous.dedup.test.js.map +1 -0
- package/dist/__tests__/autonomous.doomLoop.test.d.ts +2 -0
- package/dist/__tests__/autonomous.doomLoop.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.doomLoop.test.js +126 -0
- package/dist/__tests__/autonomous.doomLoop.test.js.map +1 -0
- package/dist/__tests__/autonomous.getAvailableActions.test.d.ts +2 -0
- package/dist/__tests__/autonomous.getAvailableActions.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.getAvailableActions.test.js +233 -0
- package/dist/__tests__/autonomous.getAvailableActions.test.js.map +1 -0
- package/dist/__tests__/autonomous.guardrails.test.d.ts +2 -0
- package/dist/__tests__/autonomous.guardrails.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.guardrails.test.js +215 -0
- package/dist/__tests__/autonomous.guardrails.test.js.map +1 -0
- package/dist/__tests__/autonomous.hooks.test.d.ts +2 -0
- package/dist/__tests__/autonomous.hooks.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.hooks.test.js +107 -0
- package/dist/__tests__/autonomous.hooks.test.js.map +1 -0
- package/dist/__tests__/autonomous.latentSpace.test.d.ts +2 -0
- package/dist/__tests__/autonomous.latentSpace.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.latentSpace.test.js +224 -0
- package/dist/__tests__/autonomous.latentSpace.test.js.map +1 -0
- package/dist/__tests__/autonomous.lifecycle.test.d.ts +2 -0
- package/dist/__tests__/autonomous.lifecycle.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.lifecycle.test.js +147 -0
- package/dist/__tests__/autonomous.lifecycle.test.js.map +1 -0
- package/dist/__tests__/autonomous.loadedSkillRefs.test.d.ts +2 -0
- package/dist/__tests__/autonomous.loadedSkillRefs.test.d.ts.map +1 -0
- package/dist/__tests__/autonomous.loadedSkillRefs.test.js +150 -0
- package/dist/__tests__/autonomous.loadedSkillRefs.test.js.map +1 -0
- package/dist/__tests__/chatEngine.episodicHook.test.d.ts +2 -0
- package/dist/__tests__/chatEngine.episodicHook.test.d.ts.map +1 -0
- package/dist/__tests__/chatEngine.episodicHook.test.js +160 -0
- package/dist/__tests__/chatEngine.episodicHook.test.js.map +1 -0
- package/dist/__tests__/chatEngine.test.d.ts +2 -0
- package/dist/__tests__/chatEngine.test.d.ts.map +1 -0
- package/dist/__tests__/chatEngine.test.js +482 -0
- package/dist/__tests__/chatEngine.test.js.map +1 -0
- package/dist/__tests__/codegen-drift.test.d.ts +23 -0
- package/dist/__tests__/codegen-drift.test.d.ts.map +1 -0
- package/dist/__tests__/codegen-drift.test.js +185 -0
- package/dist/__tests__/codegen-drift.test.js.map +1 -0
- package/dist/__tests__/contentSafety.test.d.ts +2 -0
- package/dist/__tests__/contentSafety.test.d.ts.map +1 -0
- package/dist/__tests__/contentSafety.test.js +90 -0
- package/dist/__tests__/contentSafety.test.js.map +1 -0
- package/dist/__tests__/conversation/compactionMemory.test.d.ts +2 -0
- package/dist/__tests__/conversation/compactionMemory.test.d.ts.map +1 -0
- package/dist/__tests__/conversation/compactionMemory.test.js +447 -0
- package/dist/__tests__/conversation/compactionMemory.test.js.map +1 -0
- package/dist/__tests__/conversation/modelThresholdsParity.test.d.ts +2 -0
- package/dist/__tests__/conversation/modelThresholdsParity.test.d.ts.map +1 -0
- package/dist/__tests__/conversation/modelThresholdsParity.test.js +79 -0
- package/dist/__tests__/conversation/modelThresholdsParity.test.js.map +1 -0
- package/dist/__tests__/doomLoop.test.d.ts +6 -0
- package/dist/__tests__/doomLoop.test.d.ts.map +1 -0
- package/dist/__tests__/doomLoop.test.js +144 -0
- package/dist/__tests__/doomLoop.test.js.map +1 -0
- package/dist/__tests__/guardrails.test.d.ts +2 -0
- package/dist/__tests__/guardrails.test.d.ts.map +1 -0
- package/dist/__tests__/guardrails.test.js +236 -0
- package/dist/__tests__/guardrails.test.js.map +1 -0
- package/dist/__tests__/helpers/mockRuntime.d.ts +11 -0
- package/dist/__tests__/helpers/mockRuntime.d.ts.map +1 -0
- package/dist/__tests__/helpers/mockRuntime.js +146 -0
- package/dist/__tests__/helpers/mockRuntime.js.map +1 -0
- package/dist/__tests__/hooks.test.d.ts +9 -0
- package/dist/__tests__/hooks.test.d.ts.map +1 -0
- package/dist/__tests__/hooks.test.js +192 -0
- package/dist/__tests__/hooks.test.js.map +1 -0
- package/dist/__tests__/manifestActivationHook.test.d.ts +2 -0
- package/dist/__tests__/manifestActivationHook.test.d.ts.map +1 -0
- package/dist/__tests__/manifestActivationHook.test.js +312 -0
- package/dist/__tests__/manifestActivationHook.test.js.map +1 -0
- package/dist/__tests__/memory.test.d.ts +2 -0
- package/dist/__tests__/memory.test.d.ts.map +1 -0
- package/dist/__tests__/memory.test.js +192 -0
- package/dist/__tests__/memory.test.js.map +1 -0
- package/dist/__tests__/onChainActions.parity.test.d.ts +12 -0
- package/dist/__tests__/onChainActions.parity.test.d.ts.map +1 -0
- package/dist/__tests__/onChainActions.parity.test.js +104 -0
- package/dist/__tests__/onChainActions.parity.test.js.map +1 -0
- package/dist/__tests__/querySegmentation.test.d.ts +2 -0
- package/dist/__tests__/querySegmentation.test.d.ts.map +1 -0
- package/dist/__tests__/querySegmentation.test.js +187 -0
- package/dist/__tests__/querySegmentation.test.js.map +1 -0
- package/dist/__tests__/sandbox.test.d.ts +13 -0
- package/dist/__tests__/sandbox.test.d.ts.map +1 -0
- package/dist/__tests__/sandbox.test.js +413 -0
- package/dist/__tests__/sandbox.test.js.map +1 -0
- package/dist/__tests__/signing.test.d.ts +2 -0
- package/dist/__tests__/signing.test.d.ts.map +1 -0
- package/dist/__tests__/signing.test.js +260 -0
- package/dist/__tests__/signing.test.js.map +1 -0
- package/dist/__tests__/wakeUpStack.test.d.ts +2 -0
- package/dist/__tests__/wakeUpStack.test.d.ts.map +1 -0
- package/dist/__tests__/wakeUpStack.test.js +239 -0
- package/dist/__tests__/wakeUpStack.test.js.map +1 -0
- package/dist/actionCatalog.d.ts +57 -0
- package/dist/actionCatalog.d.ts.map +1 -0
- package/dist/actionCatalog.generated.d.ts +4 -0
- package/dist/actionCatalog.generated.d.ts.map +1 -0
- package/dist/actionCatalog.generated.js +2194 -0
- package/dist/actionCatalog.generated.js.map +1 -0
- package/dist/actionCatalog.js +214 -0
- package/dist/actionCatalog.js.map +1 -0
- package/dist/api-marketplace.d.ts +111 -0
- package/dist/api-marketplace.d.ts.map +1 -0
- package/dist/api-marketplace.js +154 -0
- package/dist/api-marketplace.js.map +1 -0
- package/dist/artifactEmbeddings.d.ts +69 -0
- package/dist/artifactEmbeddings.d.ts.map +1 -0
- package/dist/artifactEmbeddings.js +52 -0
- package/dist/artifactEmbeddings.js.map +1 -0
- package/dist/autonomous.d.ts +271 -0
- package/dist/autonomous.d.ts.map +1 -0
- package/dist/autonomous.js +3517 -0
- package/dist/autonomous.js.map +1 -0
- package/dist/bounties.d.ts +112 -0
- package/dist/bounties.d.ts.map +1 -0
- package/dist/bounties.js +140 -0
- package/dist/bounties.js.map +1 -0
- package/dist/bundles.d.ts +174 -0
- package/dist/bundles.d.ts.map +1 -0
- package/dist/bundles.js +208 -0
- package/dist/bundles.js.map +1 -0
- package/dist/channels.d.ts +131 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +227 -0
- package/dist/channels.js.map +1 -0
- package/dist/chat/chatEngine.d.ts +138 -0
- package/dist/chat/chatEngine.d.ts.map +1 -0
- package/dist/chat/chatEngine.js +613 -0
- package/dist/chat/chatEngine.js.map +1 -0
- package/dist/chat/index.d.ts +30 -0
- package/dist/chat/index.d.ts.map +1 -0
- package/dist/chat/index.js +29 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/terminal.d.ts +19 -0
- package/dist/chat/terminal.d.ts.map +1 -0
- package/dist/chat/terminal.js +17 -0
- package/dist/chat/terminal.js.map +1 -0
- package/dist/chat/terminals/discordTerminal.d.ts +22 -0
- package/dist/chat/terminals/discordTerminal.d.ts.map +1 -0
- package/dist/chat/terminals/discordTerminal.js +132 -0
- package/dist/chat/terminals/discordTerminal.js.map +1 -0
- package/dist/chat/terminals/openclawTerminal.d.ts +43 -0
- package/dist/chat/terminals/openclawTerminal.d.ts.map +1 -0
- package/dist/chat/terminals/openclawTerminal.js +186 -0
- package/dist/chat/terminals/openclawTerminal.js.map +1 -0
- package/dist/chat/terminals/stdinTerminal.d.ts +18 -0
- package/dist/chat/terminals/stdinTerminal.d.ts.map +1 -0
- package/dist/chat/terminals/stdinTerminal.js +58 -0
- package/dist/chat/terminals/stdinTerminal.js.map +1 -0
- package/dist/chat/terminals/telegramTerminal.d.ts +27 -0
- package/dist/chat/terminals/telegramTerminal.d.ts.map +1 -0
- package/dist/chat/terminals/telegramTerminal.js +123 -0
- package/dist/chat/terminals/telegramTerminal.js.map +1 -0
- package/dist/cognitiveWorkspace.d.ts +107 -0
- package/dist/cognitiveWorkspace.d.ts.map +1 -0
- package/dist/cognitiveWorkspace.js +94 -0
- package/dist/cognitiveWorkspace.js.map +1 -0
- package/dist/communities.d.ts +40 -0
- package/dist/communities.d.ts.map +1 -0
- package/dist/communities.js +53 -0
- package/dist/communities.js.map +1 -0
- package/dist/connection.d.ts +90 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +429 -0
- package/dist/connection.js.map +1 -0
- package/dist/contentSafety.d.ts +64 -0
- package/dist/contentSafety.d.ts.map +1 -0
- package/dist/contentSafety.js +119 -0
- package/dist/contentSafety.js.map +1 -0
- package/dist/conversation/compactionMemory.d.ts +124 -0
- package/dist/conversation/compactionMemory.d.ts.map +1 -0
- package/dist/conversation/compactionMemory.js +379 -0
- package/dist/conversation/compactionMemory.js.map +1 -0
- package/dist/conversation/conversationLogStore.d.ts +111 -0
- package/dist/conversation/conversationLogStore.d.ts.map +1 -0
- package/dist/conversation/conversationLogStore.js +248 -0
- package/dist/conversation/conversationLogStore.js.map +1 -0
- package/dist/conversation/conversationMemory.d.ts +59 -0
- package/dist/conversation/conversationMemory.d.ts.map +1 -0
- package/dist/conversation/conversationMemory.js +32 -0
- package/dist/conversation/conversationMemory.js.map +1 -0
- package/dist/conversation/index.d.ts +16 -0
- package/dist/conversation/index.d.ts.map +1 -0
- package/dist/conversation/index.js +5 -0
- package/dist/conversation/index.js.map +1 -0
- package/dist/conversation/modelLimits.d.ts +43 -0
- package/dist/conversation/modelLimits.d.ts.map +1 -0
- package/dist/conversation/modelLimits.js +67 -0
- package/dist/conversation/modelLimits.js.map +1 -0
- package/dist/cro.d.ts +243 -0
- package/dist/cro.d.ts.map +1 -0
- package/dist/cro.js +263 -0
- package/dist/cro.js.map +1 -0
- package/dist/defaultGuardrails.d.ts +21 -0
- package/dist/defaultGuardrails.d.ts.map +1 -0
- package/dist/defaultGuardrails.js +90 -0
- package/dist/defaultGuardrails.js.map +1 -0
- package/dist/delegations.d.ts +63 -0
- package/dist/delegations.d.ts.map +1 -0
- package/dist/delegations.js +41 -0
- package/dist/delegations.js.map +1 -0
- package/dist/discovery.d.ts +172 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +300 -0
- package/dist/discovery.js.map +1 -0
- package/dist/doomLoop.d.ts +52 -0
- package/dist/doomLoop.d.ts.map +1 -0
- package/dist/doomLoop.js +173 -0
- package/dist/doomLoop.js.map +1 -0
- package/dist/economy.d.ts +244 -0
- package/dist/economy.d.ts.map +1 -0
- package/dist/economy.js +263 -0
- package/dist/economy.js.map +1 -0
- package/dist/email.d.ts +125 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +91 -0
- package/dist/email.js.map +1 -0
- package/dist/embeddingExchange.d.ts +141 -0
- package/dist/embeddingExchange.d.ts.map +1 -0
- package/dist/embeddingExchange.js +95 -0
- package/dist/embeddingExchange.js.map +1 -0
- package/dist/episodicMemoryHook.d.ts +39 -0
- package/dist/episodicMemoryHook.d.ts.map +1 -0
- package/dist/episodicMemoryHook.js +58 -0
- package/dist/episodicMemoryHook.js.map +1 -0
- package/dist/evaluator.d.ts +113 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +144 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/events.d.ts +58 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +86 -0
- package/dist/events.js.map +1 -0
- package/dist/formatters.d.ts +31 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +227 -0
- package/dist/formatters.js.map +1 -0
- package/dist/gpu.d.ts +137 -0
- package/dist/gpu.d.ts.map +1 -0
- package/dist/gpu.js +166 -0
- package/dist/gpu.js.map +1 -0
- package/dist/guardrails.d.ts +182 -0
- package/dist/guardrails.d.ts.map +1 -0
- package/dist/guardrails.js +277 -0
- package/dist/guardrails.js.map +1 -0
- package/dist/guilds.d.ts +158 -0
- package/dist/guilds.d.ts.map +1 -0
- package/dist/guilds.js +205 -0
- package/dist/guilds.js.map +1 -0
- package/dist/heartbeat.d.ts +43 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +72 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/hooks.d.ts +172 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +91 -0
- package/dist/hooks.js.map +1 -0
- package/dist/identity.d.ts +61 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +76 -0
- package/dist/identity.js.map +1 -0
- package/dist/inbox.d.ts +77 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +98 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +321 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +361 -0
- package/dist/index.js.map +1 -0
- package/dist/insights.d.ts +166 -0
- package/dist/insights.d.ts.map +1 -0
- package/dist/insights.js +100 -0
- package/dist/insights.js.map +1 -0
- package/dist/intents.d.ts +132 -0
- package/dist/intents.d.ts.map +1 -0
- package/dist/intents.js +81 -0
- package/dist/intents.js.map +1 -0
- package/dist/knowledgeContext.d.ts +68 -0
- package/dist/knowledgeContext.d.ts.map +1 -0
- package/dist/knowledgeContext.js +109 -0
- package/dist/knowledgeContext.js.map +1 -0
- package/dist/leaderboard.d.ts +30 -0
- package/dist/leaderboard.d.ts.map +1 -0
- package/dist/leaderboard.js +34 -0
- package/dist/leaderboard.js.map +1 -0
- package/dist/manifest.d.ts +127 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +123 -0
- package/dist/manifest.js.map +1 -0
- package/dist/manifestActivationHook.d.ts +72 -0
- package/dist/manifestActivationHook.d.ts.map +1 -0
- package/dist/manifestActivationHook.js +180 -0
- package/dist/manifestActivationHook.js.map +1 -0
- package/dist/marketplace.d.ts +156 -0
- package/dist/marketplace.d.ts.map +1 -0
- package/dist/marketplace.js +215 -0
- package/dist/marketplace.js.map +1 -0
- package/dist/matching.d.ts +192 -0
- package/dist/matching.d.ts.map +1 -0
- package/dist/matching.js +138 -0
- package/dist/matching.js.map +1 -0
- package/dist/memory.d.ts +287 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +379 -0
- package/dist/memory.js.map +1 -0
- package/dist/mining.d.ts +155 -0
- package/dist/mining.d.ts.map +1 -0
- package/dist/mining.js +365 -0
- package/dist/mining.js.map +1 -0
- package/dist/oracle.d.ts +30 -0
- package/dist/oracle.d.ts.map +1 -0
- package/dist/oracle.js +31 -0
- package/dist/oracle.js.map +1 -0
- package/dist/policies.d.ts +132 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +62 -0
- package/dist/policies.js.map +1 -0
- package/dist/proactive.d.ts +197 -0
- package/dist/proactive.d.ts.map +1 -0
- package/dist/proactive.js +229 -0
- package/dist/proactive.js.map +1 -0
- package/dist/projects.d.ts +307 -0
- package/dist/projects.d.ts.map +1 -0
- package/dist/projects.js +438 -0
- package/dist/projects.js.map +1 -0
- package/dist/querySegmentation.d.ts +54 -0
- package/dist/querySegmentation.d.ts.map +1 -0
- package/dist/querySegmentation.js +80 -0
- package/dist/querySegmentation.js.map +1 -0
- package/dist/sandbox.d.ts +156 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +425 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/signalActionMap.d.ts +59 -0
- package/dist/signalActionMap.d.ts.map +1 -0
- package/dist/signalActionMap.js +305 -0
- package/dist/signalActionMap.js.map +1 -0
- package/dist/signing.d.ts +94 -0
- package/dist/signing.d.ts.map +1 -0
- package/dist/signing.js +158 -0
- package/dist/signing.js.map +1 -0
- package/dist/social.d.ts +176 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +232 -0
- package/dist/social.js.map +1 -0
- package/dist/specialization.d.ts +108 -0
- package/dist/specialization.d.ts.map +1 -0
- package/dist/specialization.js +104 -0
- package/dist/specialization.js.map +1 -0
- package/dist/swarms.d.ts +106 -0
- package/dist/swarms.d.ts.map +1 -0
- package/dist/swarms.js +99 -0
- package/dist/swarms.js.map +1 -0
- package/dist/teaching.d.ts +171 -0
- package/dist/teaching.d.ts.map +1 -0
- package/dist/teaching.js +87 -0
- package/dist/teaching.js.map +1 -0
- package/dist/tools.d.ts +223 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +325 -0
- package/dist/tools.js.map +1 -0
- package/dist/treasury-ops.d.ts +101 -0
- package/dist/treasury-ops.d.ts.map +1 -0
- package/dist/treasury-ops.js +59 -0
- package/dist/treasury-ops.js.map +1 -0
- package/dist/types.d.ts +1193 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/wakeUpStack.d.ts +94 -0
- package/dist/wakeUpStack.d.ts.map +1 -0
- package/dist/wakeUpStack.js +215 -0
- package/dist/wakeUpStack.js.map +1 -0
- package/dist/workspace.d.ts +318 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +207 -0
- package/dist/workspace.js.map +1 -0
- package/dist/xmtp.d.ts +85 -0
- package/dist/xmtp.d.ts.map +1 -0
- package/dist/xmtp.js +250 -0
- package/dist/xmtp.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { HookRegistry } from "../hooks.js";
|
|
2
|
+
import type { InferenceMessage } from "../types.js";
|
|
3
|
+
import type { ConversationMemory } from "./conversationMemory.js";
|
|
4
|
+
import type { ConversationLogStore } from "./conversationLogStore.js";
|
|
5
|
+
/** Caller-supplied summarizer. We do NOT pin a model dependency. */
|
|
6
|
+
export type CompactFn = (messages: InferenceMessage[], systemPrompt: string) => Promise<string>;
|
|
7
|
+
export interface CompactionConfig {
|
|
8
|
+
/** Looked up in `MODEL_THRESHOLDS`; unknown models fall back to the default. */
|
|
9
|
+
modelName: string;
|
|
10
|
+
/** Trigger compaction at `safetyRatio × compactAt` tokens. Default 0.8. */
|
|
11
|
+
safetyRatio?: number;
|
|
12
|
+
/** Override the threshold's `preserveRecent` count. */
|
|
13
|
+
preserveRecent?: number;
|
|
14
|
+
/** Prepended to the compaction request. Default from `modelLimits.ts`. */
|
|
15
|
+
systemPromptPreamble?: string;
|
|
16
|
+
/** Where to persist messages. Omit for purely in-memory operation. */
|
|
17
|
+
store?: ConversationLogStore;
|
|
18
|
+
/** Stable session id. Auto-generated when omitted. */
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
/** Whether `buildTools()` returns search/read tool defs. Default true. */
|
|
21
|
+
enableMemoryTools?: boolean;
|
|
22
|
+
/** Hook registry for `memory_compacted` events. Defaults to runtime singleton. */
|
|
23
|
+
hooks?: HookRegistry;
|
|
24
|
+
/** How to summarize. Caller injects so the SDK doesn't pull in an LLM dep. */
|
|
25
|
+
compactFn: CompactFn;
|
|
26
|
+
/** Override the token estimator. Defaults to gateway-parity heuristic. */
|
|
27
|
+
estimateTokens?: (messages: InferenceMessage[]) => number;
|
|
28
|
+
/** Maximum chars stored per summary. Default 2000 (matches gateway). */
|
|
29
|
+
maxSummaryChars?: number;
|
|
30
|
+
}
|
|
31
|
+
/** Runtime-observable counters. */
|
|
32
|
+
export interface CompactionStats {
|
|
33
|
+
messageCount: number;
|
|
34
|
+
pendingToolCalls: number;
|
|
35
|
+
compactionCount: number;
|
|
36
|
+
estimatedTokens: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Lightweight tool-definition shape returned by `buildTools()`. We don't reuse
|
|
40
|
+
* the registry's `ToolDefinition` because these tools live entirely inside the
|
|
41
|
+
* agent process — they have no cost, no rate limit, no autonomy bracket.
|
|
42
|
+
*/
|
|
43
|
+
export interface MemoryToolDefinition {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
/** JSON Schema describing the tool's arguments (LLM-facing). */
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object";
|
|
49
|
+
properties: Record<string, {
|
|
50
|
+
type: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
minimum?: number;
|
|
53
|
+
}>;
|
|
54
|
+
required?: string[];
|
|
55
|
+
};
|
|
56
|
+
/** Local handler. The session id is captured in the closure — never an LLM arg. */
|
|
57
|
+
handler: (args: Record<string, unknown>) => Promise<unknown>;
|
|
58
|
+
}
|
|
59
|
+
export declare class CompactionMemory implements ConversationMemory {
|
|
60
|
+
readonly sessionId: string;
|
|
61
|
+
private readonly threshold;
|
|
62
|
+
private readonly safetyRatio;
|
|
63
|
+
private readonly preserveRecent;
|
|
64
|
+
private readonly preamble;
|
|
65
|
+
private readonly store;
|
|
66
|
+
private readonly hooks;
|
|
67
|
+
private readonly compactFn;
|
|
68
|
+
private readonly estimateTokensFn;
|
|
69
|
+
private readonly enableMemoryTools;
|
|
70
|
+
private readonly maxSummaryChars;
|
|
71
|
+
/** Linear list of messages that will be sent to the LLM next call. */
|
|
72
|
+
private messages;
|
|
73
|
+
/** Indices into `messages` immediately AFTER each closed unit. */
|
|
74
|
+
private unitBoundaries;
|
|
75
|
+
/** Outstanding tool calls awaiting their replies. */
|
|
76
|
+
private pendingToolCalls;
|
|
77
|
+
/** Monotonic counter, used in `LogEntry.compactionNumber`. */
|
|
78
|
+
private compactionCount;
|
|
79
|
+
/**
|
|
80
|
+
* Number of original messages that have been collapsed away by all prior
|
|
81
|
+
* compactions. Used to project log-store indices into the live array.
|
|
82
|
+
*/
|
|
83
|
+
private removedFromHead;
|
|
84
|
+
/** Serializes `_autoCompact` so two near-simultaneous calls don't double-compact. */
|
|
85
|
+
private compactionInFlight;
|
|
86
|
+
constructor(config: CompactionConfig);
|
|
87
|
+
addMessage(msg: InferenceMessage): Promise<void>;
|
|
88
|
+
getContext(): InferenceMessage[];
|
|
89
|
+
reset(): Promise<void>;
|
|
90
|
+
stats(): CompactionStats;
|
|
91
|
+
/**
|
|
92
|
+
* Reconstruct a `CompactionMemory` from its persisted JSONL log.
|
|
93
|
+
*
|
|
94
|
+
* Algorithm: replay entries in append order, maintaining the live message
|
|
95
|
+
* array. A `message` entry appends. A `compaction` entry replaces the head
|
|
96
|
+
* `messagesCompacted` messages with the summary system message. A `reset`
|
|
97
|
+
* entry clears the array. Truncated tail lines are skipped by `store.read`.
|
|
98
|
+
*
|
|
99
|
+
* This walk-and-fold approach preserves the invariant that messages added
|
|
100
|
+
* BETWEEN the last addMessage that triggered compaction and the compaction
|
|
101
|
+
* write itself stay in the tail — exactly mirroring the in-memory state
|
|
102
|
+
* after `_autoCompact`.
|
|
103
|
+
*/
|
|
104
|
+
static restoreFromLog(sessionId: string, store: ConversationLogStore, config: Omit<CompactionConfig, "sessionId" | "store">): Promise<CompactionMemory>;
|
|
105
|
+
/**
|
|
106
|
+
* Tool definitions the caller can hand to the LLM so the agent can recover
|
|
107
|
+
* detail the summary dropped. The session id is captured in the closure —
|
|
108
|
+
* the LLM never supplies it. Returns `[]` when `enableMemoryTools: false`
|
|
109
|
+
* or no `store` is configured (no log → nothing to search).
|
|
110
|
+
*/
|
|
111
|
+
buildTools(): MemoryToolDefinition[];
|
|
112
|
+
private updateUnitState;
|
|
113
|
+
private shouldCompact;
|
|
114
|
+
private runCompactionOnce;
|
|
115
|
+
/**
|
|
116
|
+
* Pick the latest closed unit boundary that leaves at least `preserveRecent`
|
|
117
|
+
* messages in the tail, summarize everything before it, and replace the
|
|
118
|
+
* collapsed prefix with one `role: "system"` summary message.
|
|
119
|
+
*/
|
|
120
|
+
private _autoCompact;
|
|
121
|
+
/** Recompute unitBoundaries + pendingToolCalls from `this.messages` in place. */
|
|
122
|
+
private replayUnitState;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=compactionMemory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compactionMemory.d.ts","sourceRoot":"","sources":["../../src/conversation/compactionMemory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `CompactionMemory` — turn-boundary-aware conversation memory with optional
|
|
3
|
+
* JSONL persistence.
|
|
4
|
+
*
|
|
5
|
+
* **Why turn boundaries.** When you compact mid-turn, you risk leaving an
|
|
6
|
+
* orphaned `role: "tool"` reply in the preserved tail without its calling
|
|
7
|
+
* `assistant` message in the prefix — which most LLMs will reject. We track
|
|
8
|
+
* three unit kinds (lifted in spirit from Motus's `compaction_memory.py`):
|
|
9
|
+
*
|
|
10
|
+
* - **Unit A**: a single `role: "user"` message.
|
|
11
|
+
* - **Unit B**: an `assistant` message with N `toolCalls`, followed by all N
|
|
12
|
+
* matching `role: "tool"` replies.
|
|
13
|
+
* - **Unit C**: an `assistant` message with no `toolCalls` (final answer).
|
|
14
|
+
*
|
|
15
|
+
* Compaction only fires when `pendingToolCalls === 0` AND the message stream
|
|
16
|
+
* has at least one closed unit boundary that we can roll up.
|
|
17
|
+
*
|
|
18
|
+
* **Compaction output.** The replaced prefix is collapsed into a single
|
|
19
|
+
* `role: "system"` message whose content is `"[Conversation Summary]\n" +
|
|
20
|
+
* sanitizeForPrompt(summary)` — same shape `gateway/sessionCompactor.ts:225`
|
|
21
|
+
* emits, so downstream prompt-assembly code doesn't have to branch.
|
|
22
|
+
*
|
|
23
|
+
* **Persistence.** Every `addMessage` and every compaction writes a single
|
|
24
|
+
* JSONL line via the configured `ConversationLogStore`. Restart-recovery is
|
|
25
|
+
* exposed as `CompactionMemory.restoreFromLog(sessionId, store, cfg)`.
|
|
26
|
+
*
|
|
27
|
+
* **Hook integration.** Successful compactions emit a fire-and-forget
|
|
28
|
+
* `memory_compacted` event via the configured `HookRegistry` (defaults to the
|
|
29
|
+
* runtime singleton). Slow subscribers don't delay the next `addMessage`.
|
|
30
|
+
*
|
|
31
|
+
* @module conversation/compactionMemory
|
|
32
|
+
*/
|
|
33
|
+
import { randomUUID } from "node:crypto";
|
|
34
|
+
import { sanitizeForPrompt } from "../contentSafety.js";
|
|
35
|
+
import { hooks as defaultHooks } from "../hooks.js";
|
|
36
|
+
import { DEFAULT_COMPACTION_SYSTEM_PROMPT, estimateTokens as defaultEstimateTokens, getModelThreshold, } from "./modelLimits.js";
|
|
37
|
+
const DEFAULT_SAFETY_RATIO = 0.8;
|
|
38
|
+
const DEFAULT_MAX_SUMMARY_CHARS = 2000;
|
|
39
|
+
const DEFAULT_SEARCH_LIMIT = 5;
|
|
40
|
+
const MAX_SEARCH_LIMIT = 20;
|
|
41
|
+
export class CompactionMemory {
|
|
42
|
+
sessionId;
|
|
43
|
+
threshold;
|
|
44
|
+
safetyRatio;
|
|
45
|
+
preserveRecent;
|
|
46
|
+
preamble;
|
|
47
|
+
store;
|
|
48
|
+
hooks;
|
|
49
|
+
compactFn;
|
|
50
|
+
estimateTokensFn;
|
|
51
|
+
enableMemoryTools;
|
|
52
|
+
maxSummaryChars;
|
|
53
|
+
// Live state ──────────────────────────────────────────────
|
|
54
|
+
/** Linear list of messages that will be sent to the LLM next call. */
|
|
55
|
+
messages = [];
|
|
56
|
+
/** Indices into `messages` immediately AFTER each closed unit. */
|
|
57
|
+
unitBoundaries = [];
|
|
58
|
+
/** Outstanding tool calls awaiting their replies. */
|
|
59
|
+
pendingToolCalls = 0;
|
|
60
|
+
/** Monotonic counter, used in `LogEntry.compactionNumber`. */
|
|
61
|
+
compactionCount = 0;
|
|
62
|
+
/**
|
|
63
|
+
* Number of original messages that have been collapsed away by all prior
|
|
64
|
+
* compactions. Used to project log-store indices into the live array.
|
|
65
|
+
*/
|
|
66
|
+
removedFromHead = 0;
|
|
67
|
+
/** Serializes `_autoCompact` so two near-simultaneous calls don't double-compact. */
|
|
68
|
+
compactionInFlight = null;
|
|
69
|
+
constructor(config) {
|
|
70
|
+
this.sessionId = config.sessionId ?? randomUUID();
|
|
71
|
+
this.threshold = getModelThreshold(config.modelName);
|
|
72
|
+
this.safetyRatio = config.safetyRatio ?? DEFAULT_SAFETY_RATIO;
|
|
73
|
+
this.preserveRecent = config.preserveRecent ?? this.threshold.preserveRecent;
|
|
74
|
+
this.preamble = config.systemPromptPreamble ?? DEFAULT_COMPACTION_SYSTEM_PROMPT;
|
|
75
|
+
this.store = config.store;
|
|
76
|
+
this.hooks = config.hooks ?? defaultHooks;
|
|
77
|
+
this.compactFn = config.compactFn;
|
|
78
|
+
this.estimateTokensFn = config.estimateTokens ?? defaultEstimateTokens;
|
|
79
|
+
this.enableMemoryTools = config.enableMemoryTools ?? true;
|
|
80
|
+
this.maxSummaryChars = config.maxSummaryChars ?? DEFAULT_MAX_SUMMARY_CHARS;
|
|
81
|
+
}
|
|
82
|
+
// ── ConversationMemory ──────────────────────────────────
|
|
83
|
+
async addMessage(msg) {
|
|
84
|
+
this.messages.push(msg);
|
|
85
|
+
this.updateUnitState(msg);
|
|
86
|
+
if (this.store) {
|
|
87
|
+
await this.store.append(this.sessionId, {
|
|
88
|
+
kind: "message",
|
|
89
|
+
ts: new Date().toISOString(),
|
|
90
|
+
msg,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// Compaction is only safe at a closed-unit boundary. Defer otherwise.
|
|
94
|
+
if (this.pendingToolCalls === 0 && this.shouldCompact()) {
|
|
95
|
+
await this.runCompactionOnce();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
getContext() {
|
|
99
|
+
return this.messages.slice();
|
|
100
|
+
}
|
|
101
|
+
async reset() {
|
|
102
|
+
this.messages = [];
|
|
103
|
+
this.unitBoundaries = [];
|
|
104
|
+
this.pendingToolCalls = 0;
|
|
105
|
+
this.compactionCount = 0;
|
|
106
|
+
this.removedFromHead = 0;
|
|
107
|
+
if (this.store) {
|
|
108
|
+
await this.store.append(this.sessionId, { kind: "reset", ts: new Date().toISOString() });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
stats() {
|
|
112
|
+
return {
|
|
113
|
+
messageCount: this.messages.length,
|
|
114
|
+
pendingToolCalls: this.pendingToolCalls,
|
|
115
|
+
compactionCount: this.compactionCount,
|
|
116
|
+
estimatedTokens: this.estimateTokensFn(this.messages),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// ── Restore ─────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Reconstruct a `CompactionMemory` from its persisted JSONL log.
|
|
122
|
+
*
|
|
123
|
+
* Algorithm: replay entries in append order, maintaining the live message
|
|
124
|
+
* array. A `message` entry appends. A `compaction` entry replaces the head
|
|
125
|
+
* `messagesCompacted` messages with the summary system message. A `reset`
|
|
126
|
+
* entry clears the array. Truncated tail lines are skipped by `store.read`.
|
|
127
|
+
*
|
|
128
|
+
* This walk-and-fold approach preserves the invariant that messages added
|
|
129
|
+
* BETWEEN the last addMessage that triggered compaction and the compaction
|
|
130
|
+
* write itself stay in the tail — exactly mirroring the in-memory state
|
|
131
|
+
* after `_autoCompact`.
|
|
132
|
+
*/
|
|
133
|
+
static async restoreFromLog(sessionId, store, config) {
|
|
134
|
+
const memory = new CompactionMemory({ ...config, sessionId, store });
|
|
135
|
+
if (!(await store.exists(sessionId)))
|
|
136
|
+
return memory;
|
|
137
|
+
const entries = await store.read(sessionId);
|
|
138
|
+
for (const entry of entries) {
|
|
139
|
+
if (entry.kind === "reset") {
|
|
140
|
+
memory.messages = [];
|
|
141
|
+
memory.compactionCount = 0;
|
|
142
|
+
memory.removedFromHead = 0;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (entry.kind === "message") {
|
|
146
|
+
memory.messages.push(entry.msg);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
// compaction
|
|
150
|
+
const drop = Math.min(entry.messagesCompacted, memory.messages.length);
|
|
151
|
+
const tail = memory.messages.slice(drop);
|
|
152
|
+
memory.messages = [
|
|
153
|
+
{ role: "system", content: `[Conversation Summary]\n${entry.summary}` },
|
|
154
|
+
...tail,
|
|
155
|
+
];
|
|
156
|
+
memory.compactionCount = entry.compactionNumber;
|
|
157
|
+
memory.removedFromHead = entry.replacedRange[1];
|
|
158
|
+
}
|
|
159
|
+
// Re-derive turn-boundary state from the restored messages.
|
|
160
|
+
memory.replayUnitState();
|
|
161
|
+
return memory;
|
|
162
|
+
}
|
|
163
|
+
// ── Tool exposure (agent-internal) ──────────────────────
|
|
164
|
+
/**
|
|
165
|
+
* Tool definitions the caller can hand to the LLM so the agent can recover
|
|
166
|
+
* detail the summary dropped. The session id is captured in the closure —
|
|
167
|
+
* the LLM never supplies it. Returns `[]` when `enableMemoryTools: false`
|
|
168
|
+
* or no `store` is configured (no log → nothing to search).
|
|
169
|
+
*/
|
|
170
|
+
buildTools() {
|
|
171
|
+
if (!this.enableMemoryTools || !this.store)
|
|
172
|
+
return [];
|
|
173
|
+
const store = this.store;
|
|
174
|
+
const sessionId = this.sessionId;
|
|
175
|
+
const search = {
|
|
176
|
+
name: "search_conversation_log",
|
|
177
|
+
description: "Substring search across the current conversation's archived messages " +
|
|
178
|
+
"(including those collapsed by an earlier summary). Returns the most " +
|
|
179
|
+
"recent matches first.",
|
|
180
|
+
inputSchema: {
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: {
|
|
183
|
+
query: { type: "string", description: "Substring to look for (case-insensitive)." },
|
|
184
|
+
maxResults: {
|
|
185
|
+
type: "number",
|
|
186
|
+
description: "Cap on returned matches (default 5, max 20).",
|
|
187
|
+
minimum: 1,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
required: ["query"],
|
|
191
|
+
},
|
|
192
|
+
handler: async (args) => {
|
|
193
|
+
const query = typeof args.query === "string" ? args.query : "";
|
|
194
|
+
let cap = typeof args.maxResults === "number" ? Math.floor(args.maxResults) : DEFAULT_SEARCH_LIMIT;
|
|
195
|
+
if (!Number.isFinite(cap) || cap < 1)
|
|
196
|
+
cap = DEFAULT_SEARCH_LIMIT;
|
|
197
|
+
if (cap > MAX_SEARCH_LIMIT)
|
|
198
|
+
cap = MAX_SEARCH_LIMIT;
|
|
199
|
+
// sessionId is closure-captured. Any `sessionId` arg from the LLM is
|
|
200
|
+
// silently ignored — defense-in-depth against tool-arg poisoning.
|
|
201
|
+
return await store.searchMessages(sessionId, query, cap);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
const read = {
|
|
205
|
+
name: "read_compaction_summary",
|
|
206
|
+
description: "Return the summary text produced by a past compaction of the current " +
|
|
207
|
+
"session, by 1-indexed compaction number.",
|
|
208
|
+
inputSchema: {
|
|
209
|
+
type: "object",
|
|
210
|
+
properties: {
|
|
211
|
+
compactionNumber: {
|
|
212
|
+
type: "number",
|
|
213
|
+
description: "1-indexed; matches the counter exposed by stats().compactionCount.",
|
|
214
|
+
minimum: 1,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
required: ["compactionNumber"],
|
|
218
|
+
},
|
|
219
|
+
handler: async (args) => {
|
|
220
|
+
const num = typeof args.compactionNumber === "number" ? Math.floor(args.compactionNumber) : 0;
|
|
221
|
+
if (!Number.isFinite(num) || num < 1) {
|
|
222
|
+
throw new Error("compactionNumber must be a positive integer");
|
|
223
|
+
}
|
|
224
|
+
const entries = await store.read(sessionId);
|
|
225
|
+
const match = entries.find((e) => e.kind === "compaction" && e.compactionNumber === num);
|
|
226
|
+
if (!match) {
|
|
227
|
+
throw new Error(`compaction ${num} not found for session`);
|
|
228
|
+
}
|
|
229
|
+
return match;
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
return [search, read];
|
|
233
|
+
}
|
|
234
|
+
// ── Internals ───────────────────────────────────────────
|
|
235
|
+
updateUnitState(msg) {
|
|
236
|
+
const idx = this.messages.length; // index AFTER the just-pushed msg
|
|
237
|
+
if (msg.role === "assistant") {
|
|
238
|
+
const calls = msg.toolCalls?.length ?? 0;
|
|
239
|
+
if (calls > 0) {
|
|
240
|
+
this.pendingToolCalls += calls;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// Closes a Unit C immediately.
|
|
244
|
+
this.unitBoundaries.push(idx);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else if (msg.role === "tool") {
|
|
248
|
+
// Decrement, clamping at zero in case of orphan tool results.
|
|
249
|
+
this.pendingToolCalls = Math.max(0, this.pendingToolCalls - 1);
|
|
250
|
+
if (this.pendingToolCalls === 0) {
|
|
251
|
+
this.unitBoundaries.push(idx);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else if (msg.role === "user") {
|
|
255
|
+
// The unit BEFORE this user message is already closed (Unit C closed it
|
|
256
|
+
// at the prior assistant message, OR Unit B closed it at the last tool
|
|
257
|
+
// reply). Record the user message; compaction check happens after.
|
|
258
|
+
this.unitBoundaries.push(idx);
|
|
259
|
+
}
|
|
260
|
+
// role: "system" never closes a unit. Typically used for the compaction
|
|
261
|
+
// summary itself or for a static system prompt — neither is a turn boundary.
|
|
262
|
+
}
|
|
263
|
+
shouldCompact() {
|
|
264
|
+
const triggerAt = Math.floor(this.threshold.compactAt * this.safetyRatio);
|
|
265
|
+
return this.estimateTokensFn(this.messages) >= triggerAt;
|
|
266
|
+
}
|
|
267
|
+
async runCompactionOnce() {
|
|
268
|
+
if (this.compactionInFlight) {
|
|
269
|
+
await this.compactionInFlight;
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
this.compactionInFlight = this._autoCompact().finally(() => {
|
|
273
|
+
this.compactionInFlight = null;
|
|
274
|
+
});
|
|
275
|
+
await this.compactionInFlight;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Pick the latest closed unit boundary that leaves at least `preserveRecent`
|
|
279
|
+
* messages in the tail, summarize everything before it, and replace the
|
|
280
|
+
* collapsed prefix with one `role: "system"` summary message.
|
|
281
|
+
*/
|
|
282
|
+
async _autoCompact() {
|
|
283
|
+
const tailReserve = this.preserveRecent;
|
|
284
|
+
if (this.messages.length <= tailReserve + 1)
|
|
285
|
+
return;
|
|
286
|
+
// Pick the largest boundary ≤ messages.length - tailReserve.
|
|
287
|
+
const cutoffMax = this.messages.length - tailReserve;
|
|
288
|
+
let boundary = -1;
|
|
289
|
+
for (const b of this.unitBoundaries) {
|
|
290
|
+
if (b <= cutoffMax && b > boundary)
|
|
291
|
+
boundary = b;
|
|
292
|
+
}
|
|
293
|
+
if (boundary <= 0)
|
|
294
|
+
return; // nothing closed yet
|
|
295
|
+
// Don't bother if the first message is already a system summary AND no real
|
|
296
|
+
// progress can be made (boundary would replace just that summary).
|
|
297
|
+
if (boundary === 1 && this.messages[0].role === "system")
|
|
298
|
+
return;
|
|
299
|
+
const toCompact = this.messages.slice(0, boundary);
|
|
300
|
+
const tail = this.messages.slice(boundary);
|
|
301
|
+
let summary;
|
|
302
|
+
try {
|
|
303
|
+
summary = await this.compactFn(toCompact, this.preamble);
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
// Compaction failure is non-fatal — leave the messages in place and try
|
|
307
|
+
// again on the next addMessage. Mirrors gateway behavior. Emit a
|
|
308
|
+
// `compaction_failed` hook so operators can alert on a downed summarizer
|
|
309
|
+
// instead of silently watching context grow unbounded.
|
|
310
|
+
this.hooks.emitFireAndForget("compaction_failed", {
|
|
311
|
+
sessionId: this.sessionId,
|
|
312
|
+
error: err,
|
|
313
|
+
attemptedMessages: toCompact.length,
|
|
314
|
+
});
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const sanitized = sanitizeForPrompt(summary, this.maxSummaryChars);
|
|
318
|
+
const summaryMessage = {
|
|
319
|
+
role: "system",
|
|
320
|
+
content: `[Conversation Summary]\n${sanitized}`,
|
|
321
|
+
};
|
|
322
|
+
const replacedFrom = this.removedFromHead;
|
|
323
|
+
const replacedTo = this.removedFromHead + boundary;
|
|
324
|
+
const messagesCompacted = boundary;
|
|
325
|
+
const summaryTokens = Math.ceil(sanitized.length / 4);
|
|
326
|
+
this.compactionCount += 1;
|
|
327
|
+
this.messages = [summaryMessage, ...tail];
|
|
328
|
+
this.removedFromHead += boundary;
|
|
329
|
+
// Recompute boundaries against the new `messages` array. The summary
|
|
330
|
+
// message itself is `system` (no boundary); reapply unit logic for the
|
|
331
|
+
// preserved tail so future compactions still know where to cut.
|
|
332
|
+
this.replayUnitState();
|
|
333
|
+
if (this.store) {
|
|
334
|
+
await this.store.append(this.sessionId, {
|
|
335
|
+
kind: "compaction",
|
|
336
|
+
ts: new Date().toISOString(),
|
|
337
|
+
compactionNumber: this.compactionCount,
|
|
338
|
+
replacedRange: [replacedFrom, replacedTo],
|
|
339
|
+
messagesCompacted,
|
|
340
|
+
summary: sanitized,
|
|
341
|
+
summaryTokens,
|
|
342
|
+
model: "n/a", // caller's compactFn knows the actual model; we don't need it here
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
this.hooks.emitFireAndForget("memory_compacted", {
|
|
346
|
+
sessionId: this.sessionId,
|
|
347
|
+
compactionNumber: this.compactionCount,
|
|
348
|
+
messagesCompacted,
|
|
349
|
+
summaryTokens,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
/** Recompute unitBoundaries + pendingToolCalls from `this.messages` in place. */
|
|
353
|
+
replayUnitState() {
|
|
354
|
+
this.unitBoundaries = [];
|
|
355
|
+
this.pendingToolCalls = 0;
|
|
356
|
+
for (let i = 0; i < this.messages.length; i++) {
|
|
357
|
+
const m = this.messages[i];
|
|
358
|
+
const idxAfter = i + 1;
|
|
359
|
+
if (m.role === "assistant") {
|
|
360
|
+
const calls = m.toolCalls?.length ?? 0;
|
|
361
|
+
if (calls > 0) {
|
|
362
|
+
this.pendingToolCalls += calls;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
this.unitBoundaries.push(idxAfter);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else if (m.role === "tool") {
|
|
369
|
+
this.pendingToolCalls = Math.max(0, this.pendingToolCalls - 1);
|
|
370
|
+
if (this.pendingToolCalls === 0)
|
|
371
|
+
this.unitBoundaries.push(idxAfter);
|
|
372
|
+
}
|
|
373
|
+
else if (m.role === "user") {
|
|
374
|
+
this.unitBoundaries.push(idxAfter);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=compactionMemory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compactionMemory.js","sourceRoot":"","sources":["../../src/conversation/compactionMemory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { InferenceMessage } from "../types.js";
|
|
2
|
+
/** Single JSONL line. `kind` discriminates the union. */
|
|
3
|
+
export type LogEntry = {
|
|
4
|
+
kind: "message";
|
|
5
|
+
ts: string;
|
|
6
|
+
msg: InferenceMessage;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "compaction";
|
|
9
|
+
ts: string;
|
|
10
|
+
compactionNumber: number;
|
|
11
|
+
/** Half-open range `[fromIdx, toIdx)` into the log entries that were replaced. */
|
|
12
|
+
replacedRange: [number, number];
|
|
13
|
+
messagesCompacted: number;
|
|
14
|
+
summary: string;
|
|
15
|
+
summaryTokens: number;
|
|
16
|
+
model: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "reset";
|
|
19
|
+
ts: string;
|
|
20
|
+
};
|
|
21
|
+
export interface ConversationLogStore {
|
|
22
|
+
/** Append a single entry. Implementations must be append-atomic per call. */
|
|
23
|
+
append(sessionId: string, entry: LogEntry): Promise<void>;
|
|
24
|
+
/** True iff at least one entry has been appended for `sessionId`. */
|
|
25
|
+
exists(sessionId: string): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Read every entry in append order. Implementations skip malformed lines
|
|
28
|
+
* (e.g. truncated tails from a crashed write) rather than throwing.
|
|
29
|
+
*/
|
|
30
|
+
read(sessionId: string): Promise<LogEntry[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Substring search across the message bodies of `sessionId`. Returns the
|
|
33
|
+
* matching messages, most recent first, capped at `maxResults`.
|
|
34
|
+
*/
|
|
35
|
+
searchMessages(sessionId: string, query: string, maxResults: number): Promise<InferenceMessage[]>;
|
|
36
|
+
/** Enumerate every session that has been written. */
|
|
37
|
+
listSessions(): Promise<string[]>;
|
|
38
|
+
/** Delete the session's log. Idempotent. */
|
|
39
|
+
delete(sessionId: string): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* In-process log store for tests. Round-trips identically to
|
|
43
|
+
* `LocalConversationLogStore` but never touches disk.
|
|
44
|
+
*/
|
|
45
|
+
export declare class InMemoryConversationLogStore implements ConversationLogStore {
|
|
46
|
+
private readonly logs;
|
|
47
|
+
append(sessionId: string, entry: LogEntry): Promise<void>;
|
|
48
|
+
exists(sessionId: string): Promise<boolean>;
|
|
49
|
+
read(sessionId: string): Promise<LogEntry[]>;
|
|
50
|
+
searchMessages(sessionId: string, query: string, maxResults: number): Promise<InferenceMessage[]>;
|
|
51
|
+
listSessions(): Promise<string[]>;
|
|
52
|
+
delete(sessionId: string): Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
export interface LocalConversationLogStoreOptions {
|
|
55
|
+
/**
|
|
56
|
+
* Base directory for JSONL files. Defaults to
|
|
57
|
+
* `~/.nookplot/conversations/`. Created on first write.
|
|
58
|
+
*/
|
|
59
|
+
baseDir?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* JSONL-on-disk log. One file per session, named by SHA-256 of the
|
|
63
|
+
* `sessionId` so the on-disk layout is path-traversal-safe even if a caller
|
|
64
|
+
* pipes attacker-controlled input as the session id.
|
|
65
|
+
*
|
|
66
|
+
* The original `sessionId` is stored alongside the hashed filename in a
|
|
67
|
+
* sidecar map (`<baseDir>/_sessions.json`) so {@link listSessions} can return
|
|
68
|
+
* the human-readable identifiers.
|
|
69
|
+
*
|
|
70
|
+
* **Concurrency.** Appends and sidecar writes within ONE instance are
|
|
71
|
+
* serialized via a per-instance promise chain — calling `append()` ten times
|
|
72
|
+
* in parallel produces ten lines in call order, not ten interleaved partial
|
|
73
|
+
* writes. Concurrent writers across *processes* (same baseDir, different
|
|
74
|
+
* runtime instances) are still unsafe; the store is intended for single-
|
|
75
|
+
* process agents. Use separate `baseDir`s per process to avoid cross-process
|
|
76
|
+
* races on `_sessions.json`.
|
|
77
|
+
*/
|
|
78
|
+
export declare class LocalConversationLogStore implements ConversationLogStore {
|
|
79
|
+
private readonly baseDir;
|
|
80
|
+
private indexLoaded;
|
|
81
|
+
private readonly index;
|
|
82
|
+
private indexFilePromise;
|
|
83
|
+
/**
|
|
84
|
+
* In-process mutation chain. Any method that reads *and* writes shared state
|
|
85
|
+
* (`index`, `_sessions.json`, session JSONL files) awaits the previous op
|
|
86
|
+
* before starting. Read-only ops can skip this.
|
|
87
|
+
*/
|
|
88
|
+
private mutationChain;
|
|
89
|
+
constructor(opts?: LocalConversationLogStoreOptions);
|
|
90
|
+
/**
|
|
91
|
+
* Run `fn` serialized against any other mutation on this instance. Failures
|
|
92
|
+
* in `fn` are surfaced to the caller but do NOT poison the chain — the next
|
|
93
|
+
* call starts from a resolved state.
|
|
94
|
+
*/
|
|
95
|
+
private serialize;
|
|
96
|
+
/** Filename for a session: 32-char SHA-256 prefix + `.jsonl`. */
|
|
97
|
+
private fileFor;
|
|
98
|
+
private indexPath;
|
|
99
|
+
private ensureIndex;
|
|
100
|
+
private persistIndex;
|
|
101
|
+
private pathFor;
|
|
102
|
+
append(sessionId: string, entry: LogEntry): Promise<void>;
|
|
103
|
+
exists(sessionId: string): Promise<boolean>;
|
|
104
|
+
read(sessionId: string): Promise<LogEntry[]>;
|
|
105
|
+
searchMessages(sessionId: string, query: string, maxResults: number): Promise<InferenceMessage[]>;
|
|
106
|
+
listSessions(): Promise<string[]>;
|
|
107
|
+
delete(sessionId: string): Promise<void>;
|
|
108
|
+
/** Test helper — list every JSONL file currently on disk. */
|
|
109
|
+
_debugListFiles(): Promise<string[]>;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=conversationLogStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversationLogStore.d.ts","sourceRoot":"","sources":["../../src/conversation/conversationLogStore.ts"],"names":[],"mappings":"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"}
|