@illuma-ai/agents 1.1.25 → 1.3.0
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/cjs/agents/AgentContext.cjs +20 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/spawnPath.cjs +104 -0
- package/dist/cjs/common/spawnPath.cjs.map +1 -0
- package/dist/cjs/graphs/Graph.cjs +87 -31
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/HandoffRegistry.cjs +143 -0
- package/dist/cjs/graphs/HandoffRegistry.cjs.map +1 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs +587 -184
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/graphs/phases/flushLoop.cjs +214 -0
- package/dist/cjs/graphs/phases/flushLoop.cjs.map +1 -0
- package/dist/cjs/graphs/phases/memoryFlushPhase.cjs +102 -0
- package/dist/cjs/graphs/phases/memoryFlushPhase.cjs.map +1 -0
- package/dist/cjs/llm/bedrock/index.cjs +4 -3
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +115 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/memory/citations.cjs +69 -0
- package/dist/cjs/memory/citations.cjs.map +1 -0
- package/dist/cjs/memory/compositeBackend.cjs +60 -0
- package/dist/cjs/memory/compositeBackend.cjs.map +1 -0
- package/dist/cjs/memory/constants.cjs +232 -0
- package/dist/cjs/memory/constants.cjs.map +1 -0
- package/dist/cjs/memory/embeddings.cjs +151 -0
- package/dist/cjs/memory/embeddings.cjs.map +1 -0
- package/dist/cjs/memory/factory.cjs +95 -0
- package/dist/cjs/memory/factory.cjs.map +1 -0
- package/dist/cjs/memory/migrate.cjs +81 -0
- package/dist/cjs/memory/migrate.cjs.map +1 -0
- package/dist/cjs/memory/mmr.cjs +138 -0
- package/dist/cjs/memory/mmr.cjs.map +1 -0
- package/dist/cjs/memory/paths.cjs +217 -0
- package/dist/cjs/memory/paths.cjs.map +1 -0
- package/dist/cjs/memory/pgvectorStore.cjs +225 -0
- package/dist/cjs/memory/pgvectorStore.cjs.map +1 -0
- package/dist/cjs/memory/recallTracking.cjs +98 -0
- package/dist/cjs/memory/recallTracking.cjs.map +1 -0
- package/dist/cjs/memory/schema.sql +51 -0
- package/dist/cjs/memory/temporalDecay.cjs +118 -0
- package/dist/cjs/memory/temporalDecay.cjs.map +1 -0
- package/dist/cjs/nodes/ApprovalGateNode.cjs +1 -1
- package/dist/cjs/nodes/ApprovalGateNode.cjs.map +1 -1
- package/dist/cjs/prompts/memoryFlushPrompt.cjs +49 -0
- package/dist/cjs/prompts/memoryFlushPrompt.cjs.map +1 -0
- package/dist/cjs/run.cjs +16 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +4 -4
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/AskUser.cjs +6 -1
- package/dist/cjs/tools/AskUser.cjs.map +1 -1
- package/dist/cjs/tools/BrowserTools.cjs +1 -1
- package/dist/cjs/tools/BrowserTools.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +127 -10
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/approval/constants.cjs +2 -2
- package/dist/cjs/tools/approval/constants.cjs.map +1 -1
- package/dist/cjs/tools/memory/index.cjs +58 -0
- package/dist/cjs/tools/memory/index.cjs.map +1 -0
- package/dist/cjs/tools/memory/memoryAppendTool.cjs +69 -0
- package/dist/cjs/tools/memory/memoryAppendTool.cjs.map +1 -0
- package/dist/cjs/tools/memory/memoryGetTool.cjs +49 -0
- package/dist/cjs/tools/memory/memoryGetTool.cjs.map +1 -0
- package/dist/cjs/tools/memory/memorySearchTool.cjs +65 -0
- package/dist/cjs/tools/memory/memorySearchTool.cjs.map +1 -0
- package/dist/cjs/tools/memory/shared.cjs +106 -0
- package/dist/cjs/tools/memory/shared.cjs.map +1 -0
- package/dist/cjs/types/graph.cjs.map +1 -1
- package/dist/cjs/utils/childAgentContext.cjs +242 -0
- package/dist/cjs/utils/childAgentContext.cjs.map +1 -0
- package/dist/cjs/utils/events.cjs +36 -4
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/cjs/utils/finishReasons.cjs +44 -0
- package/dist/cjs/utils/finishReasons.cjs.map +1 -0
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/logging.cjs +34 -0
- package/dist/cjs/utils/logging.cjs.map +1 -0
- package/dist/cjs/utils/toolCallNormalization.cjs +250 -0
- package/dist/cjs/utils/toolCallNormalization.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +20 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/spawnPath.mjs +95 -0
- package/dist/esm/common/spawnPath.mjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +87 -31
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/HandoffRegistry.mjs +141 -0
- package/dist/esm/graphs/HandoffRegistry.mjs.map +1 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs +587 -184
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/graphs/phases/flushLoop.mjs +209 -0
- package/dist/esm/graphs/phases/flushLoop.mjs.map +1 -0
- package/dist/esm/graphs/phases/memoryFlushPhase.mjs +99 -0
- package/dist/esm/graphs/phases/memoryFlushPhase.mjs.map +1 -0
- package/dist/esm/llm/bedrock/index.mjs +4 -3
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/main.mjs +21 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/memory/citations.mjs +64 -0
- package/dist/esm/memory/citations.mjs.map +1 -0
- package/dist/esm/memory/compositeBackend.mjs +58 -0
- package/dist/esm/memory/compositeBackend.mjs.map +1 -0
- package/dist/esm/memory/constants.mjs +198 -0
- package/dist/esm/memory/constants.mjs.map +1 -0
- package/dist/esm/memory/embeddings.mjs +148 -0
- package/dist/esm/memory/embeddings.mjs.map +1 -0
- package/dist/esm/memory/factory.mjs +93 -0
- package/dist/esm/memory/factory.mjs.map +1 -0
- package/dist/esm/memory/migrate.mjs +78 -0
- package/dist/esm/memory/migrate.mjs.map +1 -0
- package/dist/esm/memory/mmr.mjs +130 -0
- package/dist/esm/memory/mmr.mjs.map +1 -0
- package/dist/esm/memory/paths.mjs +207 -0
- package/dist/esm/memory/paths.mjs.map +1 -0
- package/dist/esm/memory/pgvectorStore.mjs +223 -0
- package/dist/esm/memory/pgvectorStore.mjs.map +1 -0
- package/dist/esm/memory/recallTracking.mjs +94 -0
- package/dist/esm/memory/recallTracking.mjs.map +1 -0
- package/dist/esm/memory/schema.sql +51 -0
- package/dist/esm/memory/temporalDecay.mjs +110 -0
- package/dist/esm/memory/temporalDecay.mjs.map +1 -0
- package/dist/esm/nodes/ApprovalGateNode.mjs +1 -1
- package/dist/esm/nodes/ApprovalGateNode.mjs.map +1 -1
- package/dist/esm/prompts/memoryFlushPrompt.mjs +44 -0
- package/dist/esm/prompts/memoryFlushPrompt.mjs.map +1 -0
- package/dist/esm/run.mjs +16 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +4 -4
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/AskUser.mjs +6 -1
- package/dist/esm/tools/AskUser.mjs.map +1 -1
- package/dist/esm/tools/BrowserTools.mjs +1 -1
- package/dist/esm/tools/BrowserTools.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +128 -11
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/approval/constants.mjs +2 -2
- package/dist/esm/tools/approval/constants.mjs.map +1 -1
- package/dist/esm/tools/memory/index.mjs +46 -0
- package/dist/esm/tools/memory/index.mjs.map +1 -0
- package/dist/esm/tools/memory/memoryAppendTool.mjs +67 -0
- package/dist/esm/tools/memory/memoryAppendTool.mjs.map +1 -0
- package/dist/esm/tools/memory/memoryGetTool.mjs +47 -0
- package/dist/esm/tools/memory/memoryGetTool.mjs.map +1 -0
- package/dist/esm/tools/memory/memorySearchTool.mjs +63 -0
- package/dist/esm/tools/memory/memorySearchTool.mjs.map +1 -0
- package/dist/esm/tools/memory/shared.mjs +98 -0
- package/dist/esm/tools/memory/shared.mjs.map +1 -0
- package/dist/esm/types/graph.mjs.map +1 -1
- package/dist/esm/utils/childAgentContext.mjs +237 -0
- package/dist/esm/utils/childAgentContext.mjs.map +1 -0
- package/dist/esm/utils/events.mjs +36 -5
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/esm/utils/finishReasons.mjs +41 -0
- package/dist/esm/utils/finishReasons.mjs.map +1 -0
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/logging.mjs +31 -0
- package/dist/esm/utils/logging.mjs.map +1 -0
- package/dist/esm/utils/toolCallNormalization.mjs +247 -0
- package/dist/esm/utils/toolCallNormalization.mjs.map +1 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/common/spawnPath.d.ts +59 -0
- package/dist/types/graphs/HandoffRegistry.d.ts +97 -0
- package/dist/types/graphs/MultiAgentGraph.d.ts +58 -18
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/graphs/phases/flushLoop.d.ts +106 -0
- package/dist/types/graphs/phases/memoryFlushPhase.d.ts +100 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/memory/__tests__/mockBackend.d.ts +40 -0
- package/dist/types/memory/citations.d.ts +39 -0
- package/dist/types/memory/compositeBackend.d.ts +30 -0
- package/dist/types/memory/constants.d.ts +121 -0
- package/dist/types/memory/embeddings.d.ts +15 -0
- package/dist/types/memory/factory.d.ts +23 -0
- package/dist/types/memory/index.d.ts +21 -0
- package/dist/types/memory/migrate.d.ts +14 -0
- package/dist/types/memory/mmr.d.ts +50 -0
- package/dist/types/memory/paths.d.ts +107 -0
- package/dist/types/memory/pgvectorStore.d.ts +56 -0
- package/dist/types/memory/recallTracking.d.ts +30 -0
- package/dist/types/memory/temporalDecay.d.ts +53 -0
- package/dist/types/memory/types.d.ts +182 -0
- package/dist/types/prompts/memoryFlushPrompt.d.ts +54 -0
- package/dist/types/run.d.ts +1 -0
- package/dist/types/tools/AskUser.d.ts +1 -1
- package/dist/types/tools/BrowserTools.d.ts +2 -2
- package/dist/types/tools/approval/constants.d.ts +2 -2
- package/dist/types/tools/memory/index.d.ts +39 -0
- package/dist/types/tools/memory/memoryAppendTool.d.ts +27 -0
- package/dist/types/tools/memory/memoryGetTool.d.ts +22 -0
- package/dist/types/tools/memory/memorySearchTool.d.ts +22 -0
- package/dist/types/tools/memory/shared.d.ts +106 -0
- package/dist/types/types/graph.d.ts +16 -3
- package/dist/types/utils/childAgentContext.d.ts +99 -0
- package/dist/types/utils/events.d.ts +21 -0
- package/dist/types/utils/finishReasons.d.ts +32 -0
- package/dist/types/utils/logging.d.ts +2 -0
- package/dist/types/utils/toolCallNormalization.d.ts +44 -0
- package/package.json +6 -4
- package/src/agents/AgentContext.ts +26 -3
- package/src/common/__tests__/enum.test.ts +4 -2
- package/src/common/__tests__/spawnPath.test.ts +110 -0
- package/src/common/index.ts +1 -0
- package/src/common/spawnPath.ts +101 -0
- package/src/graphs/Graph.ts +94 -43
- package/src/graphs/HandoffRegistry.ts +199 -0
- package/src/graphs/MultiAgentGraph.ts +694 -226
- package/src/graphs/__tests__/HandoffRegistry.test.ts +410 -0
- package/src/graphs/__tests__/multi-agent-delegate.test.ts +61 -16
- package/src/graphs/__tests__/multi-agent-edges.test.ts +4 -2
- package/src/graphs/__tests__/multi-agent-nested-subgraph.test.ts +221 -0
- package/src/graphs/__tests__/structured-output.integration.test.ts +212 -118
- package/src/graphs/contextManagement.e2e.test.ts +1 -1
- package/src/graphs/index.ts +1 -0
- package/src/graphs/phases/__tests__/flushLoop.test.ts +264 -0
- package/src/graphs/phases/__tests__/memoryFlushPhase.test.ts +37 -0
- package/src/graphs/phases/__tests__/runMemoryFlush.test.ts +150 -0
- package/src/graphs/phases/flushLoop.ts +303 -0
- package/src/graphs/phases/memoryFlushPhase.ts +209 -0
- package/src/index.ts +30 -1
- package/src/llm/bedrock/index.ts +4 -5
- package/src/memory/__tests__/citations.test.ts +61 -0
- package/src/memory/__tests__/compositeBackend.test.ts +79 -0
- package/src/memory/__tests__/isolation.test.ts +206 -0
- package/src/memory/__tests__/mmr.test.ts +148 -0
- package/src/memory/__tests__/mockBackend.ts +161 -0
- package/src/memory/__tests__/paths.test.ts +168 -0
- package/src/memory/__tests__/recallTracking.test.ts +96 -0
- package/src/memory/__tests__/temporalDecay.test.ts +151 -0
- package/src/memory/citations.ts +80 -0
- package/src/memory/compositeBackend.ts +99 -0
- package/src/memory/constants.ts +229 -0
- package/src/memory/embeddings.ts +188 -0
- package/src/memory/factory.ts +111 -0
- package/src/memory/index.ts +46 -0
- package/src/memory/migrate.ts +116 -0
- package/src/memory/mmr.ts +161 -0
- package/src/memory/paths.ts +258 -0
- package/src/memory/pgvectorStore.ts +324 -0
- package/src/memory/recallTracking.ts +127 -0
- package/src/memory/schema.sql +51 -0
- package/src/memory/temporalDecay.ts +134 -0
- package/src/memory/types.ts +185 -0
- package/src/nodes/ApprovalGateNode.ts +4 -10
- package/src/nodes/__tests__/ApprovalGateNode.test.ts +11 -20
- package/src/prompts/memoryFlushPrompt.ts +78 -0
- package/src/run.ts +17 -6
- package/src/scripts/test-bedrock-handoff-autonomous.ts +56 -20
- package/src/specs/agent-handoffs-bedrock.integration.test.ts +8 -5
- package/src/specs/agent-handoffs.test.ts +8 -2
- package/src/stream.ts +4 -6
- package/src/tools/AskUser.ts +7 -2
- package/src/tools/BrowserTools.ts +3 -5
- package/src/tools/ToolNode.ts +150 -13
- package/src/tools/__tests__/ToolApproval.test.ts +22 -9
- package/src/tools/approval/__tests__/constants.test.ts +4 -4
- package/src/tools/approval/constants.ts +2 -2
- package/src/tools/memory/__tests__/memoryTools.test.ts +205 -0
- package/src/tools/memory/index.ts +96 -0
- package/src/tools/memory/memoryAppendTool.ts +101 -0
- package/src/tools/memory/memoryGetTool.ts +53 -0
- package/src/tools/memory/memorySearchTool.ts +80 -0
- package/src/tools/memory/shared.ts +169 -0
- package/src/tools/search/search.test.ts +6 -1
- package/src/types/graph.ts +16 -3
- package/src/utils/__tests__/childAgentContext.test.ts +217 -0
- package/src/utils/__tests__/finishReasons.test.ts +55 -0
- package/src/utils/__tests__/toolCallNormalization.test.ts +181 -0
- package/src/utils/childAgentContext.ts +259 -0
- package/src/utils/events.ts +37 -4
- package/src/utils/finishReasons.ts +40 -0
- package/src/utils/llm.ts +0 -1
- package/src/utils/logging.ts +45 -8
- package/src/utils/toolCallNormalization.ts +271 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry for the memory tool family.
|
|
3
|
+
*
|
|
4
|
+
* `buildMemoryTools` is the one function host calls. It returns an array
|
|
5
|
+
* of LangChain tools with scope captured in a closure — the LLM cannot
|
|
6
|
+
* override the `(agentId, userId)` pair through any tool argument.
|
|
7
|
+
*
|
|
8
|
+
* Phase 2: accepts independent `readEnabled` / `writeEnabled` flags that
|
|
9
|
+
* mirror host's existing `agent.memory_read_enabled` /
|
|
10
|
+
* `agent.memory_write_enabled` fields. Either flag can be set without the
|
|
11
|
+
* other: a read-only agent can consult memory without mutating it; a
|
|
12
|
+
* write-only agent can reflect without reading.
|
|
13
|
+
*/
|
|
14
|
+
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
15
|
+
import type { MemoryConfig, MemoryPhase } from '@/memory/types';
|
|
16
|
+
import { createMemorySearchTool } from './memorySearchTool';
|
|
17
|
+
import { createMemoryGetTool } from './memoryGetTool';
|
|
18
|
+
import { createMemoryAppendTool } from './memoryAppendTool';
|
|
19
|
+
import type { MemoryToolBinding } from './shared';
|
|
20
|
+
|
|
21
|
+
export * from './shared';
|
|
22
|
+
export { createMemorySearchTool } from './memorySearchTool';
|
|
23
|
+
export { createMemoryGetTool } from './memoryGetTool';
|
|
24
|
+
export { createMemoryAppendTool } from './memoryAppendTool';
|
|
25
|
+
|
|
26
|
+
export interface BuildMemoryToolsOptions extends MemoryConfig {
|
|
27
|
+
/**
|
|
28
|
+
* Attach `memory_search` + `memory_get`. Maps to
|
|
29
|
+
* `agent.memory_read_enabled` on the host Agent document.
|
|
30
|
+
*/
|
|
31
|
+
readEnabled?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Attach `memory_append` (still phase-gated to `memory_flushing`).
|
|
34
|
+
* Maps to `agent.memory_write_enabled` on the host Agent document.
|
|
35
|
+
*/
|
|
36
|
+
writeEnabled?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* @deprecated — legacy Phase 1 flag. When set, equivalent to
|
|
39
|
+
* `{ readEnabled: true, writeEnabled: false }`. Kept so existing tests
|
|
40
|
+
* don't break during the Phase 1→2 transition. New callers should pass
|
|
41
|
+
* `readEnabled`/`writeEnabled` explicitly.
|
|
42
|
+
*/
|
|
43
|
+
readOnly?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function buildMemoryTools(
|
|
47
|
+
options: BuildMemoryToolsOptions
|
|
48
|
+
): StructuredToolInterface[] {
|
|
49
|
+
// Back-compat for the Phase 1 readOnly flag — maps to read-only mode.
|
|
50
|
+
let readEnabled = options.readEnabled;
|
|
51
|
+
let writeEnabled = options.writeEnabled;
|
|
52
|
+
if (options.readOnly) {
|
|
53
|
+
readEnabled = true;
|
|
54
|
+
writeEnabled = false;
|
|
55
|
+
}
|
|
56
|
+
// Default: if neither flag supplied, attach both (back-compat with the
|
|
57
|
+
// pre-Phase-2 single-flag caller).
|
|
58
|
+
if (readEnabled === undefined && writeEnabled === undefined) {
|
|
59
|
+
readEnabled = true;
|
|
60
|
+
writeEnabled = true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const binding: MemoryToolBinding = {
|
|
64
|
+
backend: options.backend,
|
|
65
|
+
scope: options.scope,
|
|
66
|
+
maxInjectedChars: options.search?.maxInjectedChars,
|
|
67
|
+
searchOptions: {
|
|
68
|
+
mmr: options.search?.mmr,
|
|
69
|
+
temporalDecay: options.search?.temporalDecay,
|
|
70
|
+
citations: options.search?.citations,
|
|
71
|
+
},
|
|
72
|
+
recallTracker: options.recallTracker,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const tools: StructuredToolInterface[] = [];
|
|
76
|
+
|
|
77
|
+
if (readEnabled) {
|
|
78
|
+
tools.push(
|
|
79
|
+
createMemorySearchTool(binding) as unknown as StructuredToolInterface,
|
|
80
|
+
createMemoryGetTool(binding) as unknown as StructuredToolInterface
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (writeEnabled) {
|
|
85
|
+
const getPhase: () => MemoryPhase =
|
|
86
|
+
options.getPhase ?? ((): MemoryPhase => 'normal');
|
|
87
|
+
tools.push(
|
|
88
|
+
createMemoryAppendTool({
|
|
89
|
+
...binding,
|
|
90
|
+
getPhase,
|
|
91
|
+
}) as unknown as StructuredToolInterface
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return tools;
|
|
96
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `memory_append` — the reflection-phase-only write tool.
|
|
3
|
+
*
|
|
4
|
+
* New (not present in upstream verbatim). Upstream enforces append-only via
|
|
5
|
+
* `wrapToolMemoryFlushAppendOnlyWrite`; we combine the tool and the phase
|
|
6
|
+
* gate in one place because the agents library has a simpler graph state.
|
|
7
|
+
*
|
|
8
|
+
* Behaviour:
|
|
9
|
+
* - Outside `memory_flushing` phase: returns an error object instead of
|
|
10
|
+
* calling the backend. The LLM sees this and stops trying.
|
|
11
|
+
* - Inside `memory_flushing`: persists the note via {@link MemoryBackend.append}.
|
|
12
|
+
* - Hard-caps total appends per flush (protects against runaway writes).
|
|
13
|
+
*/
|
|
14
|
+
import { tool } from '@langchain/core/tools';
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_MAX_APPENDS_PER_FLUSH,
|
|
17
|
+
MEMORY_APPEND_DESCRIPTION,
|
|
18
|
+
MEMORY_APPEND_TOOL_NAME,
|
|
19
|
+
MEMORY_PHASE_FLUSHING,
|
|
20
|
+
} from '@/memory/constants';
|
|
21
|
+
import type { MemoryPhase } from '@/memory/types';
|
|
22
|
+
import {
|
|
23
|
+
MemoryAppendSchema,
|
|
24
|
+
toAppendInput,
|
|
25
|
+
type MemoryToolBinding,
|
|
26
|
+
} from './shared';
|
|
27
|
+
|
|
28
|
+
export interface MemoryAppendBinding extends MemoryToolBinding {
|
|
29
|
+
/**
|
|
30
|
+
* Reads the current phase at call-time. Required — without it the append
|
|
31
|
+
* tool rejects every call. Supplied by the graph runtime.
|
|
32
|
+
*/
|
|
33
|
+
getPhase: () => MemoryPhase;
|
|
34
|
+
/** Hard cap on appends per flush phase. Default 20. */
|
|
35
|
+
maxAppendsPerFlush?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface AppendResult {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
path?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
45
|
+
export function createMemoryAppendTool(binding: MemoryAppendBinding) {
|
|
46
|
+
const maxAppends =
|
|
47
|
+
binding.maxAppendsPerFlush ?? DEFAULT_MAX_APPENDS_PER_FLUSH;
|
|
48
|
+
let appendsInCurrentFlush = 0;
|
|
49
|
+
let lastSeenPhase: MemoryPhase = 'normal';
|
|
50
|
+
|
|
51
|
+
return tool(
|
|
52
|
+
async (args): Promise<string> => {
|
|
53
|
+
const phase = binding.getPhase();
|
|
54
|
+
|
|
55
|
+
// Reset counter on entry to a new flush.
|
|
56
|
+
if (
|
|
57
|
+
phase === MEMORY_PHASE_FLUSHING &&
|
|
58
|
+
lastSeenPhase !== MEMORY_PHASE_FLUSHING
|
|
59
|
+
) {
|
|
60
|
+
appendsInCurrentFlush = 0;
|
|
61
|
+
}
|
|
62
|
+
lastSeenPhase = phase;
|
|
63
|
+
|
|
64
|
+
if (phase !== MEMORY_PHASE_FLUSHING) {
|
|
65
|
+
const result: AppendResult = {
|
|
66
|
+
ok: false,
|
|
67
|
+
error:
|
|
68
|
+
'memory_append can only be called during the reflection (memory_flushing) phase',
|
|
69
|
+
};
|
|
70
|
+
return JSON.stringify(result);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (appendsInCurrentFlush >= maxAppends) {
|
|
74
|
+
const result: AppendResult = {
|
|
75
|
+
ok: false,
|
|
76
|
+
error: `memory_append hit the per-flush cap of ${maxAppends} notes`,
|
|
77
|
+
};
|
|
78
|
+
return JSON.stringify(result);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const input = toAppendInput(args);
|
|
83
|
+
await binding.backend.append(binding.scope, input);
|
|
84
|
+
appendsInCurrentFlush += 1;
|
|
85
|
+
const result: AppendResult = { ok: true, path: input.path };
|
|
86
|
+
return JSON.stringify(result);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
const result: AppendResult = {
|
|
89
|
+
ok: false,
|
|
90
|
+
error: err instanceof Error ? err.message : String(err),
|
|
91
|
+
};
|
|
92
|
+
return JSON.stringify(result);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: MEMORY_APPEND_TOOL_NAME,
|
|
97
|
+
description: MEMORY_APPEND_DESCRIPTION,
|
|
98
|
+
schema: MemoryAppendSchema,
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `memory_get` — safe snippet read.
|
|
3
|
+
*
|
|
4
|
+
* Port of upstream `createMemoryGetTool` at
|
|
5
|
+
* `upstream reference`.
|
|
6
|
+
*/
|
|
7
|
+
import { tool } from '@langchain/core/tools';
|
|
8
|
+
import {
|
|
9
|
+
MEMORY_GET_DESCRIPTION,
|
|
10
|
+
MEMORY_GET_TOOL_NAME,
|
|
11
|
+
} from '@/memory/constants';
|
|
12
|
+
import {
|
|
13
|
+
MemoryGetSchema,
|
|
14
|
+
type MemoryGetToolResult,
|
|
15
|
+
type MemoryToolBinding,
|
|
16
|
+
} from './shared';
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
19
|
+
export function createMemoryGetTool(binding: MemoryToolBinding) {
|
|
20
|
+
return tool(
|
|
21
|
+
async (args): Promise<string> => {
|
|
22
|
+
try {
|
|
23
|
+
const result = await binding.backend.get(binding.scope, {
|
|
24
|
+
path: args.path,
|
|
25
|
+
from: args.from,
|
|
26
|
+
lines: args.lines,
|
|
27
|
+
});
|
|
28
|
+
if (!result) {
|
|
29
|
+
const payload: MemoryGetToolResult = { path: args.path, text: '' };
|
|
30
|
+
return JSON.stringify(payload);
|
|
31
|
+
}
|
|
32
|
+
const payload: MemoryGetToolResult = {
|
|
33
|
+
path: result.path,
|
|
34
|
+
text: result.text,
|
|
35
|
+
};
|
|
36
|
+
return JSON.stringify(payload);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
const payload: MemoryGetToolResult = {
|
|
39
|
+
path: args.path,
|
|
40
|
+
text: '',
|
|
41
|
+
disabled: true,
|
|
42
|
+
error: err instanceof Error ? err.message : String(err),
|
|
43
|
+
};
|
|
44
|
+
return JSON.stringify(payload);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: MEMORY_GET_TOOL_NAME,
|
|
49
|
+
description: MEMORY_GET_DESCRIPTION,
|
|
50
|
+
schema: MemoryGetSchema,
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `memory_search` — the mandatory-recall tool.
|
|
3
|
+
*
|
|
4
|
+
* Port of upstream `createMemorySearchTool` at
|
|
5
|
+
* `upstream reference`. The tool description
|
|
6
|
+
* is verbatim "Mandatory recall step..." from upstream — this is the load-
|
|
7
|
+
* bearing line that turns "the agent may recall" into "the agent will recall".
|
|
8
|
+
*/
|
|
9
|
+
import { tool } from '@langchain/core/tools';
|
|
10
|
+
import {
|
|
11
|
+
MEMORY_SEARCH_DESCRIPTION,
|
|
12
|
+
MEMORY_SEARCH_TOOL_NAME,
|
|
13
|
+
} from '@/memory/constants';
|
|
14
|
+
import {
|
|
15
|
+
buildMemorySearchUnavailableResult,
|
|
16
|
+
clampResultsByInjectedChars,
|
|
17
|
+
MemorySearchSchema,
|
|
18
|
+
type MemorySearchToolResult,
|
|
19
|
+
type MemoryToolBinding,
|
|
20
|
+
} from './shared';
|
|
21
|
+
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
23
|
+
export function createMemorySearchTool(binding: MemoryToolBinding) {
|
|
24
|
+
return tool(
|
|
25
|
+
async (args): Promise<string> => {
|
|
26
|
+
try {
|
|
27
|
+
const entries = await binding.backend.search(
|
|
28
|
+
binding.scope,
|
|
29
|
+
args.query,
|
|
30
|
+
{
|
|
31
|
+
maxResults: args.maxResults,
|
|
32
|
+
minScore: args.minScore,
|
|
33
|
+
mmr: binding.searchOptions?.mmr,
|
|
34
|
+
temporalDecay: binding.searchOptions?.temporalDecay,
|
|
35
|
+
citations: binding.searchOptions?.citations,
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
const clamped = clampResultsByInjectedChars(
|
|
39
|
+
entries,
|
|
40
|
+
binding.maxInjectedChars
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// [phase2-recall-tracking] debug: fire-and-forget best-effort record
|
|
44
|
+
if (binding.recallTracker && clamped.length > 0) {
|
|
45
|
+
void binding.recallTracker
|
|
46
|
+
.record({
|
|
47
|
+
agentId: binding.scope.agentId,
|
|
48
|
+
query: args.query,
|
|
49
|
+
hits: clamped.map((e) => ({
|
|
50
|
+
id: e.id,
|
|
51
|
+
path: e.path,
|
|
52
|
+
score: e.score,
|
|
53
|
+
})),
|
|
54
|
+
})
|
|
55
|
+
.catch(() => undefined);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const payload: MemorySearchToolResult = {
|
|
59
|
+
results: clamped.map((entry) => ({
|
|
60
|
+
id: entry.id,
|
|
61
|
+
path: entry.path,
|
|
62
|
+
content: entry.content,
|
|
63
|
+
score: entry.score,
|
|
64
|
+
createdAt: entry.createdAt,
|
|
65
|
+
citation: entry.citation,
|
|
66
|
+
})),
|
|
67
|
+
};
|
|
68
|
+
return JSON.stringify(payload);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
71
|
+
return JSON.stringify(buildMemorySearchUnavailableResult(message));
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: MEMORY_SEARCH_TOOL_NAME,
|
|
76
|
+
description: MEMORY_SEARCH_DESCRIPTION,
|
|
77
|
+
schema: MemorySearchSchema,
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Zod schemas + helpers for the memory tool family.
|
|
3
|
+
*
|
|
4
|
+
* The tool schemas deliberately do NOT expose `agent_id` or `user_id`. Scope
|
|
5
|
+
* is captured in a closure at tool construction time by {@link buildMemoryTools},
|
|
6
|
+
* so even a hallucinated tool call with extra fields cannot influence it.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_MAX_INJECTED_CHARS,
|
|
11
|
+
MEMORY_PATH_PREFIX,
|
|
12
|
+
} from '@/memory/constants';
|
|
13
|
+
import type {
|
|
14
|
+
MemoryAppendInput,
|
|
15
|
+
MemoryBackend,
|
|
16
|
+
MemoryEntry,
|
|
17
|
+
MemoryScope,
|
|
18
|
+
} from '@/memory/types';
|
|
19
|
+
|
|
20
|
+
export const MemorySearchSchema = z.object({
|
|
21
|
+
query: z.string().describe('Natural-language query to search memory for'),
|
|
22
|
+
maxResults: z
|
|
23
|
+
.number()
|
|
24
|
+
.int()
|
|
25
|
+
.min(1)
|
|
26
|
+
.max(50)
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Maximum number of results to return (default 10)'),
|
|
29
|
+
minScore: z
|
|
30
|
+
.number()
|
|
31
|
+
.min(0)
|
|
32
|
+
.max(1)
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Minimum hybrid score (0..1) below which results are dropped'),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const MemoryGetSchema = z.object({
|
|
38
|
+
path: z
|
|
39
|
+
.string()
|
|
40
|
+
.describe(
|
|
41
|
+
'Memory path, e.g. "memory/decisions.md". Must start with "memory/"'
|
|
42
|
+
),
|
|
43
|
+
from: z
|
|
44
|
+
.number()
|
|
45
|
+
.int()
|
|
46
|
+
.min(1)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Starting line number (1-indexed)'),
|
|
49
|
+
lines: z
|
|
50
|
+
.number()
|
|
51
|
+
.int()
|
|
52
|
+
.min(1)
|
|
53
|
+
.optional()
|
|
54
|
+
.describe('Number of lines to read starting at `from`'),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export const MemoryAppendSchema = z.object({
|
|
58
|
+
path: z
|
|
59
|
+
.string()
|
|
60
|
+
.describe(
|
|
61
|
+
'Memory path to append to (e.g. "memory/decisions.md"). Must start with "memory/"'
|
|
62
|
+
),
|
|
63
|
+
content: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1)
|
|
66
|
+
.describe(
|
|
67
|
+
"Note content in the agent's own voice. Markdown allowed. Each call appends an immutable entry."
|
|
68
|
+
),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export type MemorySearchArgs = z.infer<typeof MemorySearchSchema>;
|
|
72
|
+
export type MemoryGetArgs = z.infer<typeof MemoryGetSchema>;
|
|
73
|
+
export type MemoryAppendArgs = z.infer<typeof MemoryAppendSchema>;
|
|
74
|
+
|
|
75
|
+
/** Shape returned by `memory_search` — serialised as the tool result string. */
|
|
76
|
+
export interface MemorySearchToolResult {
|
|
77
|
+
results: Array<
|
|
78
|
+
Pick<MemoryEntry, 'id' | 'path' | 'content' | 'score' | 'createdAt'> & {
|
|
79
|
+
citation?: string;
|
|
80
|
+
}
|
|
81
|
+
>;
|
|
82
|
+
disabled?: boolean;
|
|
83
|
+
unavailable?: boolean;
|
|
84
|
+
error?: string;
|
|
85
|
+
warning?: string;
|
|
86
|
+
action?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Shape returned by `memory_get`. */
|
|
90
|
+
export interface MemoryGetToolResult {
|
|
91
|
+
path: string;
|
|
92
|
+
text: string;
|
|
93
|
+
disabled?: boolean;
|
|
94
|
+
error?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function buildMemorySearchUnavailableResult(
|
|
98
|
+
error: string | undefined
|
|
99
|
+
): MemorySearchToolResult {
|
|
100
|
+
const reason =
|
|
101
|
+
(error ?? 'memory search unavailable').trim() ||
|
|
102
|
+
'memory search unavailable';
|
|
103
|
+
const isQuota = /insufficient_quota|quota|429/i.test(reason);
|
|
104
|
+
return {
|
|
105
|
+
results: [],
|
|
106
|
+
disabled: true,
|
|
107
|
+
unavailable: true,
|
|
108
|
+
error: reason,
|
|
109
|
+
warning: isQuota
|
|
110
|
+
? 'Memory search is unavailable because the embedding provider quota is exhausted.'
|
|
111
|
+
: 'Memory search is unavailable due to an embedding/provider error.',
|
|
112
|
+
action: isQuota
|
|
113
|
+
? 'Top up or switch embedding provider, then retry memory_search.'
|
|
114
|
+
: 'Check embedding provider configuration and retry memory_search.',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Clamp a ranked result list to a total character budget.
|
|
120
|
+
* Ported from upstream `tools.citations.ts::clampResultsByInjectedChars`.
|
|
121
|
+
*/
|
|
122
|
+
export function clampResultsByInjectedChars<T extends { content: string }>(
|
|
123
|
+
results: T[],
|
|
124
|
+
maxInjectedChars: number = DEFAULT_MAX_INJECTED_CHARS
|
|
125
|
+
): T[] {
|
|
126
|
+
const out: T[] = [];
|
|
127
|
+
let total = 0;
|
|
128
|
+
for (const result of results) {
|
|
129
|
+
const size = result.content.length ?? 0;
|
|
130
|
+
if (total + size > maxInjectedChars && out.length > 0) break;
|
|
131
|
+
out.push(result);
|
|
132
|
+
total += size;
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface MemoryToolBinding {
|
|
138
|
+
backend: MemoryBackend;
|
|
139
|
+
scope: MemoryScope;
|
|
140
|
+
maxInjectedChars?: number;
|
|
141
|
+
/** Phase 2 — per-call search options propagated into backend.search. */
|
|
142
|
+
searchOptions?: {
|
|
143
|
+
mmr?: { enabled?: boolean; lambda?: number };
|
|
144
|
+
temporalDecay?: { enabled?: boolean; halfLifeDays?: number };
|
|
145
|
+
citations?: 'on' | 'off' | 'auto';
|
|
146
|
+
};
|
|
147
|
+
/** Phase 2 — optional best-effort recall recorder. */
|
|
148
|
+
recallTracker?: {
|
|
149
|
+
record(params: {
|
|
150
|
+
agentId: string;
|
|
151
|
+
query: string;
|
|
152
|
+
hits: Array<{ id: string; path: string; score: number }>;
|
|
153
|
+
}): Promise<void>;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function assertAppendAllowed(path: string): void {
|
|
158
|
+
if (!path || !path.startsWith(MEMORY_PATH_PREFIX)) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`memory_append path must start with "${MEMORY_PATH_PREFIX}"`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Normalise an append call into the backend input shape. */
|
|
166
|
+
export function toAppendInput(args: MemoryAppendArgs): MemoryAppendInput {
|
|
167
|
+
assertAppendAllowed(args.path);
|
|
168
|
+
return { path: args.path, content: args.content };
|
|
169
|
+
}
|
|
@@ -12,7 +12,12 @@ describe('createSearchAPI', () => {
|
|
|
12
12
|
const mockSerperResponse = {
|
|
13
13
|
data: {
|
|
14
14
|
organic: [
|
|
15
|
-
{
|
|
15
|
+
{
|
|
16
|
+
position: 1,
|
|
17
|
+
title: 'Test',
|
|
18
|
+
link: 'https://example.com',
|
|
19
|
+
snippet: 'test',
|
|
20
|
+
},
|
|
16
21
|
],
|
|
17
22
|
topStories: [],
|
|
18
23
|
images: [],
|
package/src/types/graph.ts
CHANGED
|
@@ -56,6 +56,12 @@ export type AgentTransitionEvent = {
|
|
|
56
56
|
destinationAgentName: string;
|
|
57
57
|
edgeType: string; // 'handoff' | 'transfer' | 'sequence'
|
|
58
58
|
timestamp: number;
|
|
59
|
+
/** When true, this event signals handoff completion (child → parent return) */
|
|
60
|
+
isCompletion?: boolean;
|
|
61
|
+
/** Duration of child agent execution in milliseconds (only on completion events) */
|
|
62
|
+
durationMs?: number;
|
|
63
|
+
/** Length of child agent result text in characters (only on completion events) */
|
|
64
|
+
resultLength?: number;
|
|
59
65
|
};
|
|
60
66
|
|
|
61
67
|
export type GraphNode = GraphNodeKeys | typeof START;
|
|
@@ -415,6 +421,13 @@ export type GraphEdge = {
|
|
|
415
421
|
* Defaults to DEFAULT_HANDOFF_MAX_RESULT_CHARS (32768 chars, ~8192 tokens).
|
|
416
422
|
*/
|
|
417
423
|
maxResultChars?: number;
|
|
424
|
+
/**
|
|
425
|
+
* For handoff edges: When true, the child agent receives the full parent
|
|
426
|
+
* conversation history plus the orchestrator's instructions appended.
|
|
427
|
+
* When false (default), the child only receives the orchestrator's scoped
|
|
428
|
+
* instructions — isolated from the parent conversation.
|
|
429
|
+
*/
|
|
430
|
+
passthrough?: boolean;
|
|
418
431
|
/**
|
|
419
432
|
* Approval gate configuration for sequence edges.
|
|
420
433
|
* When set, inserts an approval gate node between source and destination.
|
|
@@ -696,7 +709,7 @@ export interface AgentInputs {
|
|
|
696
709
|
discoveredTools?: string[];
|
|
697
710
|
/**
|
|
698
711
|
* Optional callback for summarizing messages that were pruned from context.
|
|
699
|
-
* When provided, discarded messages are summarized by the caller
|
|
712
|
+
* When provided, discarded messages are summarized by the host caller
|
|
700
713
|
* using a cheap LLM call, and the summary is prepended to the context.
|
|
701
714
|
*/
|
|
702
715
|
summarizeCallback?: (
|
|
@@ -706,7 +719,7 @@ export interface AgentInputs {
|
|
|
706
719
|
* Pre-existing summary text loaded from persistent storage (MongoDB/Redis).
|
|
707
720
|
* When provided, this summary is injected into the initial message context
|
|
708
721
|
* so the agent has prior conversation history even on new turns.
|
|
709
|
-
* Set by
|
|
722
|
+
* Set by the host's summary store when resuming a conversation.
|
|
710
723
|
*/
|
|
711
724
|
persistedSummary?: string;
|
|
712
725
|
/**
|
|
@@ -727,7 +740,7 @@ export interface AgentInputs {
|
|
|
727
740
|
* - file_search (RAG semantic search over embedded files)
|
|
728
741
|
* - content_tool read (by contentId for exact file retrieval)
|
|
729
742
|
*
|
|
730
|
-
* Built by the orchestrator
|
|
743
|
+
* Built by the host orchestrator from message_file_map
|
|
731
744
|
* and metadata.context_files across all conversation messages.
|
|
732
745
|
*/
|
|
733
746
|
fileManifest?: FileManifestEntry[];
|