@illuma-ai/agents 1.1.28 → 1.3.1
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.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 +89 -45
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/HandoffRegistry.cjs +47 -8
- package/dist/cjs/graphs/HandoffRegistry.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +493 -267
- 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 +117 -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/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/errors.cjs +113 -0
- package/dist/cjs/utils/errors.cjs.map +1 -0
- package/dist/cjs/utils/events.cjs +36 -7
- 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.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 +89 -45
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/HandoffRegistry.mjs +47 -8
- package/dist/esm/graphs/HandoffRegistry.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +493 -267
- 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/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/errors.mjs +109 -0
- package/dist/esm/utils/errors.mjs.map +1 -0
- package/dist/esm/utils/events.mjs +36 -8
- 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 +24 -7
- package/dist/types/graphs/MultiAgentGraph.d.ts +43 -23
- 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 +10 -3
- package/dist/types/utils/childAgentContext.d.ts +99 -0
- package/dist/types/utils/errors.d.ts +37 -0
- package/dist/types/utils/events.d.ts +21 -0
- package/dist/types/utils/finishReasons.d.ts +32 -0
- package/dist/types/utils/index.d.ts +1 -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 +12 -4
- 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 +95 -61
- package/src/graphs/HandoffRegistry.ts +48 -17
- package/src/graphs/MultiAgentGraph.ts +588 -327
- package/src/graphs/__tests__/HandoffRegistry.test.ts +4 -1
- 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/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/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 +1 -1
- 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 +10 -3
- package/src/utils/__tests__/childAgentContext.test.ts +217 -0
- package/src/utils/__tests__/errors.test.ts +136 -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/errors.ts +115 -0
- package/src/utils/events.ts +37 -7
- package/src/utils/finishReasons.ts +40 -0
- package/src/utils/index.ts +1 -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,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tools = require('@langchain/core/tools');
|
|
4
|
+
var constants = require('../../memory/constants.cjs');
|
|
5
|
+
var shared = require('./shared.cjs');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `memory_get` — safe snippet read.
|
|
9
|
+
*
|
|
10
|
+
* Port of upstream `createMemoryGetTool` at
|
|
11
|
+
* `upstream reference`.
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
14
|
+
function createMemoryGetTool(binding) {
|
|
15
|
+
return tools.tool(async (args) => {
|
|
16
|
+
try {
|
|
17
|
+
const result = await binding.backend.get(binding.scope, {
|
|
18
|
+
path: args.path,
|
|
19
|
+
from: args.from,
|
|
20
|
+
lines: args.lines,
|
|
21
|
+
});
|
|
22
|
+
if (!result) {
|
|
23
|
+
const payload = { path: args.path, text: '' };
|
|
24
|
+
return JSON.stringify(payload);
|
|
25
|
+
}
|
|
26
|
+
const payload = {
|
|
27
|
+
path: result.path,
|
|
28
|
+
text: result.text,
|
|
29
|
+
};
|
|
30
|
+
return JSON.stringify(payload);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const payload = {
|
|
34
|
+
path: args.path,
|
|
35
|
+
text: '',
|
|
36
|
+
disabled: true,
|
|
37
|
+
error: err instanceof Error ? err.message : String(err),
|
|
38
|
+
};
|
|
39
|
+
return JSON.stringify(payload);
|
|
40
|
+
}
|
|
41
|
+
}, {
|
|
42
|
+
name: constants.MEMORY_GET_TOOL_NAME,
|
|
43
|
+
description: constants.MEMORY_GET_DESCRIPTION,
|
|
44
|
+
schema: shared.MemoryGetSchema,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
exports.createMemoryGetTool = createMemoryGetTool;
|
|
49
|
+
//# sourceMappingURL=memoryGetTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryGetTool.cjs","sources":["../../../../src/tools/memory/memoryGetTool.ts"],"sourcesContent":["/**\n * `memory_get` — safe snippet read.\n *\n * Port of upstream `createMemoryGetTool` at\n * `upstream reference`.\n */\nimport { tool } from '@langchain/core/tools';\nimport {\n MEMORY_GET_DESCRIPTION,\n MEMORY_GET_TOOL_NAME,\n} from '@/memory/constants';\nimport {\n MemoryGetSchema,\n type MemoryGetToolResult,\n type MemoryToolBinding,\n} from './shared';\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport function createMemoryGetTool(binding: MemoryToolBinding) {\n return tool(\n async (args): Promise<string> => {\n try {\n const result = await binding.backend.get(binding.scope, {\n path: args.path,\n from: args.from,\n lines: args.lines,\n });\n if (!result) {\n const payload: MemoryGetToolResult = { path: args.path, text: '' };\n return JSON.stringify(payload);\n }\n const payload: MemoryGetToolResult = {\n path: result.path,\n text: result.text,\n };\n return JSON.stringify(payload);\n } catch (err) {\n const payload: MemoryGetToolResult = {\n path: args.path,\n text: '',\n disabled: true,\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(payload);\n }\n },\n {\n name: MEMORY_GET_TOOL_NAME,\n description: MEMORY_GET_DESCRIPTION,\n schema: MemoryGetSchema,\n }\n );\n}\n"],"names":["tool","MEMORY_GET_TOOL_NAME","MEMORY_GET_DESCRIPTION","MemoryGetSchema"],"mappings":";;;;;;AAAA;;;;;AAKG;AAYH;AACM,SAAU,mBAAmB,CAAC,OAA0B,EAAA;AAC5D,IAAA,OAAOA,UAAI,CACT,OAAO,IAAI,KAAqB;AAC9B,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE;gBACtD,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;AAClB,aAAA,CAAC;YACF,IAAI,CAAC,MAAM,EAAE;AACX,gBAAA,MAAM,OAAO,GAAwB,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;AAClE,gBAAA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAChC;AACA,YAAA,MAAM,OAAO,GAAwB;gBACnC,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB;AACD,YAAA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAChC;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,MAAM,OAAO,GAAwB;gBACnC,IAAI,EAAE,IAAI,CAAC,IAAI;AACf,gBAAA,IAAI,EAAE,EAAE;AACR,gBAAA,QAAQ,EAAE,IAAI;AACd,gBAAA,KAAK,EAAE,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;aACxD;AACD,YAAA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAChC;AACF,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAEC,8BAAoB;AAC1B,QAAA,WAAW,EAAEC,gCAAsB;AACnC,QAAA,MAAM,EAAEC,sBAAe;AACxB,KAAA,CACF;AACH;;;;"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tools = require('@langchain/core/tools');
|
|
4
|
+
var constants = require('../../memory/constants.cjs');
|
|
5
|
+
var shared = require('./shared.cjs');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `memory_search` — the mandatory-recall tool.
|
|
9
|
+
*
|
|
10
|
+
* Port of upstream `createMemorySearchTool` at
|
|
11
|
+
* `upstream reference`. The tool description
|
|
12
|
+
* is verbatim "Mandatory recall step..." from upstream — this is the load-
|
|
13
|
+
* bearing line that turns "the agent may recall" into "the agent will recall".
|
|
14
|
+
*/
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
16
|
+
function createMemorySearchTool(binding) {
|
|
17
|
+
return tools.tool(async (args) => {
|
|
18
|
+
try {
|
|
19
|
+
const entries = await binding.backend.search(binding.scope, args.query, {
|
|
20
|
+
maxResults: args.maxResults,
|
|
21
|
+
minScore: args.minScore,
|
|
22
|
+
mmr: binding.searchOptions?.mmr,
|
|
23
|
+
temporalDecay: binding.searchOptions?.temporalDecay,
|
|
24
|
+
citations: binding.searchOptions?.citations,
|
|
25
|
+
});
|
|
26
|
+
const clamped = shared.clampResultsByInjectedChars(entries, binding.maxInjectedChars);
|
|
27
|
+
// [phase2-recall-tracking] debug: fire-and-forget best-effort record
|
|
28
|
+
if (binding.recallTracker && clamped.length > 0) {
|
|
29
|
+
void binding.recallTracker
|
|
30
|
+
.record({
|
|
31
|
+
agentId: binding.scope.agentId,
|
|
32
|
+
query: args.query,
|
|
33
|
+
hits: clamped.map((e) => ({
|
|
34
|
+
id: e.id,
|
|
35
|
+
path: e.path,
|
|
36
|
+
score: e.score,
|
|
37
|
+
})),
|
|
38
|
+
})
|
|
39
|
+
.catch(() => undefined);
|
|
40
|
+
}
|
|
41
|
+
const payload = {
|
|
42
|
+
results: clamped.map((entry) => ({
|
|
43
|
+
id: entry.id,
|
|
44
|
+
path: entry.path,
|
|
45
|
+
content: entry.content,
|
|
46
|
+
score: entry.score,
|
|
47
|
+
createdAt: entry.createdAt,
|
|
48
|
+
citation: entry.citation,
|
|
49
|
+
})),
|
|
50
|
+
};
|
|
51
|
+
return JSON.stringify(payload);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
55
|
+
return JSON.stringify(shared.buildMemorySearchUnavailableResult(message));
|
|
56
|
+
}
|
|
57
|
+
}, {
|
|
58
|
+
name: constants.MEMORY_SEARCH_TOOL_NAME,
|
|
59
|
+
description: constants.MEMORY_SEARCH_DESCRIPTION,
|
|
60
|
+
schema: shared.MemorySearchSchema,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
exports.createMemorySearchTool = createMemorySearchTool;
|
|
65
|
+
//# sourceMappingURL=memorySearchTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memorySearchTool.cjs","sources":["../../../../src/tools/memory/memorySearchTool.ts"],"sourcesContent":["/**\n * `memory_search` — the mandatory-recall tool.\n *\n * Port of upstream `createMemorySearchTool` at\n * `upstream reference`. The tool description\n * is verbatim \"Mandatory recall step...\" from upstream — this is the load-\n * bearing line that turns \"the agent may recall\" into \"the agent will recall\".\n */\nimport { tool } from '@langchain/core/tools';\nimport {\n MEMORY_SEARCH_DESCRIPTION,\n MEMORY_SEARCH_TOOL_NAME,\n} from '@/memory/constants';\nimport {\n buildMemorySearchUnavailableResult,\n clampResultsByInjectedChars,\n MemorySearchSchema,\n type MemorySearchToolResult,\n type MemoryToolBinding,\n} from './shared';\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport function createMemorySearchTool(binding: MemoryToolBinding) {\n return tool(\n async (args): Promise<string> => {\n try {\n const entries = await binding.backend.search(\n binding.scope,\n args.query,\n {\n maxResults: args.maxResults,\n minScore: args.minScore,\n mmr: binding.searchOptions?.mmr,\n temporalDecay: binding.searchOptions?.temporalDecay,\n citations: binding.searchOptions?.citations,\n }\n );\n const clamped = clampResultsByInjectedChars(\n entries,\n binding.maxInjectedChars\n );\n\n // [phase2-recall-tracking] debug: fire-and-forget best-effort record\n if (binding.recallTracker && clamped.length > 0) {\n void binding.recallTracker\n .record({\n agentId: binding.scope.agentId,\n query: args.query,\n hits: clamped.map((e) => ({\n id: e.id,\n path: e.path,\n score: e.score,\n })),\n })\n .catch(() => undefined);\n }\n\n const payload: MemorySearchToolResult = {\n results: clamped.map((entry) => ({\n id: entry.id,\n path: entry.path,\n content: entry.content,\n score: entry.score,\n createdAt: entry.createdAt,\n citation: entry.citation,\n })),\n };\n return JSON.stringify(payload);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return JSON.stringify(buildMemorySearchUnavailableResult(message));\n }\n },\n {\n name: MEMORY_SEARCH_TOOL_NAME,\n description: MEMORY_SEARCH_DESCRIPTION,\n schema: MemorySearchSchema,\n }\n );\n}\n"],"names":["tool","clampResultsByInjectedChars","buildMemorySearchUnavailableResult","MEMORY_SEARCH_TOOL_NAME","MEMORY_SEARCH_DESCRIPTION","MemorySearchSchema"],"mappings":";;;;;;AAAA;;;;;;;AAOG;AAcH;AACM,SAAU,sBAAsB,CAAC,OAA0B,EAAA;AAC/D,IAAA,OAAOA,UAAI,CACT,OAAO,IAAI,KAAqB;AAC9B,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAC1C,OAAO,CAAC,KAAK,EACb,IAAI,CAAC,KAAK,EACV;gBACE,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACvB,gBAAA,GAAG,EAAE,OAAO,CAAC,aAAa,EAAE,GAAG;AAC/B,gBAAA,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,aAAa;AACnD,gBAAA,SAAS,EAAE,OAAO,CAAC,aAAa,EAAE,SAAS;AAC5C,aAAA,CACF;YACD,MAAM,OAAO,GAAGC,kCAA2B,CACzC,OAAO,EACP,OAAO,CAAC,gBAAgB,CACzB;;YAGD,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC/C,KAAK,OAAO,CAAC;AACV,qBAAA,MAAM,CAAC;AACN,oBAAA,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO;oBAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;wBACxB,EAAE,EAAE,CAAC,CAAC,EAAE;wBACR,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,KAAK,EAAE,CAAC,CAAC,KAAK;AACf,qBAAA,CAAC,CAAC;iBACJ;AACA,qBAAA,KAAK,CAAC,MAAM,SAAS,CAAC;YAC3B;AAEA,YAAA,MAAM,OAAO,GAA2B;gBACtC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM;oBAC/B,EAAE,EAAE,KAAK,CAAC,EAAE;oBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;AACzB,iBAAA,CAAC,CAAC;aACJ;AACD,YAAA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QAChC;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;YAChE,OAAO,IAAI,CAAC,SAAS,CAACC,yCAAkC,CAAC,OAAO,CAAC,CAAC;QACpE;AACF,IAAA,CAAC,EACD;AACE,QAAA,IAAI,EAAEC,iCAAuB;AAC7B,QAAA,WAAW,EAAEC,mCAAyB;AACtC,QAAA,MAAM,EAAEC,yBAAkB;AAC3B,KAAA,CACF;AACH;;;;"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
var constants = require('../../memory/constants.cjs');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared Zod schemas + helpers for the memory tool family.
|
|
8
|
+
*
|
|
9
|
+
* The tool schemas deliberately do NOT expose `agent_id` or `user_id`. Scope
|
|
10
|
+
* is captured in a closure at tool construction time by {@link buildMemoryTools},
|
|
11
|
+
* so even a hallucinated tool call with extra fields cannot influence it.
|
|
12
|
+
*/
|
|
13
|
+
const MemorySearchSchema = zod.z.object({
|
|
14
|
+
query: zod.z.string().describe('Natural-language query to search memory for'),
|
|
15
|
+
maxResults: zod.z
|
|
16
|
+
.number()
|
|
17
|
+
.int()
|
|
18
|
+
.min(1)
|
|
19
|
+
.max(50)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Maximum number of results to return (default 10)'),
|
|
22
|
+
minScore: zod.z
|
|
23
|
+
.number()
|
|
24
|
+
.min(0)
|
|
25
|
+
.max(1)
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('Minimum hybrid score (0..1) below which results are dropped'),
|
|
28
|
+
});
|
|
29
|
+
const MemoryGetSchema = zod.z.object({
|
|
30
|
+
path: zod.z
|
|
31
|
+
.string()
|
|
32
|
+
.describe('Memory path, e.g. "memory/decisions.md". Must start with "memory/"'),
|
|
33
|
+
from: zod.z
|
|
34
|
+
.number()
|
|
35
|
+
.int()
|
|
36
|
+
.min(1)
|
|
37
|
+
.optional()
|
|
38
|
+
.describe('Starting line number (1-indexed)'),
|
|
39
|
+
lines: zod.z
|
|
40
|
+
.number()
|
|
41
|
+
.int()
|
|
42
|
+
.min(1)
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Number of lines to read starting at `from`'),
|
|
45
|
+
});
|
|
46
|
+
const MemoryAppendSchema = zod.z.object({
|
|
47
|
+
path: zod.z
|
|
48
|
+
.string()
|
|
49
|
+
.describe('Memory path to append to (e.g. "memory/decisions.md"). Must start with "memory/"'),
|
|
50
|
+
content: zod.z
|
|
51
|
+
.string()
|
|
52
|
+
.min(1)
|
|
53
|
+
.describe("Note content in the agent's own voice. Markdown allowed. Each call appends an immutable entry."),
|
|
54
|
+
});
|
|
55
|
+
function buildMemorySearchUnavailableResult(error) {
|
|
56
|
+
const reason = (error ?? 'memory search unavailable').trim() ||
|
|
57
|
+
'memory search unavailable';
|
|
58
|
+
const isQuota = /insufficient_quota|quota|429/i.test(reason);
|
|
59
|
+
return {
|
|
60
|
+
results: [],
|
|
61
|
+
disabled: true,
|
|
62
|
+
unavailable: true,
|
|
63
|
+
error: reason,
|
|
64
|
+
warning: isQuota
|
|
65
|
+
? 'Memory search is unavailable because the embedding provider quota is exhausted.'
|
|
66
|
+
: 'Memory search is unavailable due to an embedding/provider error.',
|
|
67
|
+
action: isQuota
|
|
68
|
+
? 'Top up or switch embedding provider, then retry memory_search.'
|
|
69
|
+
: 'Check embedding provider configuration and retry memory_search.',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Clamp a ranked result list to a total character budget.
|
|
74
|
+
* Ported from upstream `tools.citations.ts::clampResultsByInjectedChars`.
|
|
75
|
+
*/
|
|
76
|
+
function clampResultsByInjectedChars(results, maxInjectedChars = constants.DEFAULT_MAX_INJECTED_CHARS) {
|
|
77
|
+
const out = [];
|
|
78
|
+
let total = 0;
|
|
79
|
+
for (const result of results) {
|
|
80
|
+
const size = result.content.length ?? 0;
|
|
81
|
+
if (total + size > maxInjectedChars && out.length > 0)
|
|
82
|
+
break;
|
|
83
|
+
out.push(result);
|
|
84
|
+
total += size;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
function assertAppendAllowed(path) {
|
|
89
|
+
if (!path || !path.startsWith(constants.MEMORY_PATH_PREFIX)) {
|
|
90
|
+
throw new Error(`memory_append path must start with "${constants.MEMORY_PATH_PREFIX}"`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Normalise an append call into the backend input shape. */
|
|
94
|
+
function toAppendInput(args) {
|
|
95
|
+
assertAppendAllowed(args.path);
|
|
96
|
+
return { path: args.path, content: args.content };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
exports.MemoryAppendSchema = MemoryAppendSchema;
|
|
100
|
+
exports.MemoryGetSchema = MemoryGetSchema;
|
|
101
|
+
exports.MemorySearchSchema = MemorySearchSchema;
|
|
102
|
+
exports.assertAppendAllowed = assertAppendAllowed;
|
|
103
|
+
exports.buildMemorySearchUnavailableResult = buildMemorySearchUnavailableResult;
|
|
104
|
+
exports.clampResultsByInjectedChars = clampResultsByInjectedChars;
|
|
105
|
+
exports.toAppendInput = toAppendInput;
|
|
106
|
+
//# sourceMappingURL=shared.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.cjs","sources":["../../../../src/tools/memory/shared.ts"],"sourcesContent":["/**\n * Shared Zod schemas + helpers for the memory tool family.\n *\n * The tool schemas deliberately do NOT expose `agent_id` or `user_id`. Scope\n * is captured in a closure at tool construction time by {@link buildMemoryTools},\n * so even a hallucinated tool call with extra fields cannot influence it.\n */\nimport { z } from 'zod';\nimport {\n DEFAULT_MAX_INJECTED_CHARS,\n MEMORY_PATH_PREFIX,\n} from '@/memory/constants';\nimport type {\n MemoryAppendInput,\n MemoryBackend,\n MemoryEntry,\n MemoryScope,\n} from '@/memory/types';\n\nexport const MemorySearchSchema = z.object({\n query: z.string().describe('Natural-language query to search memory for'),\n maxResults: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe('Maximum number of results to return (default 10)'),\n minScore: z\n .number()\n .min(0)\n .max(1)\n .optional()\n .describe('Minimum hybrid score (0..1) below which results are dropped'),\n});\n\nexport const MemoryGetSchema = z.object({\n path: z\n .string()\n .describe(\n 'Memory path, e.g. \"memory/decisions.md\". Must start with \"memory/\"'\n ),\n from: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Starting line number (1-indexed)'),\n lines: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Number of lines to read starting at `from`'),\n});\n\nexport const MemoryAppendSchema = z.object({\n path: z\n .string()\n .describe(\n 'Memory path to append to (e.g. \"memory/decisions.md\"). Must start with \"memory/\"'\n ),\n content: z\n .string()\n .min(1)\n .describe(\n \"Note content in the agent's own voice. Markdown allowed. Each call appends an immutable entry.\"\n ),\n});\n\nexport type MemorySearchArgs = z.infer<typeof MemorySearchSchema>;\nexport type MemoryGetArgs = z.infer<typeof MemoryGetSchema>;\nexport type MemoryAppendArgs = z.infer<typeof MemoryAppendSchema>;\n\n/** Shape returned by `memory_search` — serialised as the tool result string. */\nexport interface MemorySearchToolResult {\n results: Array<\n Pick<MemoryEntry, 'id' | 'path' | 'content' | 'score' | 'createdAt'> & {\n citation?: string;\n }\n >;\n disabled?: boolean;\n unavailable?: boolean;\n error?: string;\n warning?: string;\n action?: string;\n}\n\n/** Shape returned by `memory_get`. */\nexport interface MemoryGetToolResult {\n path: string;\n text: string;\n disabled?: boolean;\n error?: string;\n}\n\nexport function buildMemorySearchUnavailableResult(\n error: string | undefined\n): MemorySearchToolResult {\n const reason =\n (error ?? 'memory search unavailable').trim() ||\n 'memory search unavailable';\n const isQuota = /insufficient_quota|quota|429/i.test(reason);\n return {\n results: [],\n disabled: true,\n unavailable: true,\n error: reason,\n warning: isQuota\n ? 'Memory search is unavailable because the embedding provider quota is exhausted.'\n : 'Memory search is unavailable due to an embedding/provider error.',\n action: isQuota\n ? 'Top up or switch embedding provider, then retry memory_search.'\n : 'Check embedding provider configuration and retry memory_search.',\n };\n}\n\n/**\n * Clamp a ranked result list to a total character budget.\n * Ported from upstream `tools.citations.ts::clampResultsByInjectedChars`.\n */\nexport function clampResultsByInjectedChars<T extends { content: string }>(\n results: T[],\n maxInjectedChars: number = DEFAULT_MAX_INJECTED_CHARS\n): T[] {\n const out: T[] = [];\n let total = 0;\n for (const result of results) {\n const size = result.content.length ?? 0;\n if (total + size > maxInjectedChars && out.length > 0) break;\n out.push(result);\n total += size;\n }\n return out;\n}\n\nexport interface MemoryToolBinding {\n backend: MemoryBackend;\n scope: MemoryScope;\n maxInjectedChars?: number;\n /** Phase 2 — per-call search options propagated into backend.search. */\n searchOptions?: {\n mmr?: { enabled?: boolean; lambda?: number };\n temporalDecay?: { enabled?: boolean; halfLifeDays?: number };\n citations?: 'on' | 'off' | 'auto';\n };\n /** Phase 2 — optional best-effort recall recorder. */\n recallTracker?: {\n record(params: {\n agentId: string;\n query: string;\n hits: Array<{ id: string; path: string; score: number }>;\n }): Promise<void>;\n };\n}\n\nexport function assertAppendAllowed(path: string): void {\n if (!path || !path.startsWith(MEMORY_PATH_PREFIX)) {\n throw new Error(\n `memory_append path must start with \"${MEMORY_PATH_PREFIX}\"`\n );\n }\n}\n\n/** Normalise an append call into the backend input shape. */\nexport function toAppendInput(args: MemoryAppendArgs): MemoryAppendInput {\n assertAppendAllowed(args.path);\n return { path: args.path, content: args.content };\n}\n"],"names":["z","DEFAULT_MAX_INJECTED_CHARS","MEMORY_PATH_PREFIX"],"mappings":";;;;;AAAA;;;;;;AAMG;AAaI,MAAM,kBAAkB,GAAGA,KAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAEA,KAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;AACzE,IAAA,UAAU,EAAEA;AACT,SAAA,MAAM;AACN,SAAA,GAAG;SACH,GAAG,CAAC,CAAC;SACL,GAAG,CAAC,EAAE;AACN,SAAA,QAAQ;SACR,QAAQ,CAAC,kDAAkD,CAAC;AAC/D,IAAA,QAAQ,EAAEA;AACP,SAAA,MAAM;SACN,GAAG,CAAC,CAAC;SACL,GAAG,CAAC,CAAC;AACL,SAAA,QAAQ;SACR,QAAQ,CAAC,6DAA6D,CAAC;AAC3E,CAAA;AAEM,MAAM,eAAe,GAAGA,KAAC,CAAC,MAAM,CAAC;AACtC,IAAA,IAAI,EAAEA;AACH,SAAA,MAAM;SACN,QAAQ,CACP,oEAAoE,CACrE;AACH,IAAA,IAAI,EAAEA;AACH,SAAA,MAAM;AACN,SAAA,GAAG;SACH,GAAG,CAAC,CAAC;AACL,SAAA,QAAQ;SACR,QAAQ,CAAC,kCAAkC,CAAC;AAC/C,IAAA,KAAK,EAAEA;AACJ,SAAA,MAAM;AACN,SAAA,GAAG;SACH,GAAG,CAAC,CAAC;AACL,SAAA,QAAQ;SACR,QAAQ,CAAC,4CAA4C,CAAC;AAC1D,CAAA;AAEM,MAAM,kBAAkB,GAAGA,KAAC,CAAC,MAAM,CAAC;AACzC,IAAA,IAAI,EAAEA;AACH,SAAA,MAAM;SACN,QAAQ,CACP,kFAAkF,CACnF;AACH,IAAA,OAAO,EAAEA;AACN,SAAA,MAAM;SACN,GAAG,CAAC,CAAC;SACL,QAAQ,CACP,gGAAgG,CACjG;AACJ,CAAA;AA4BK,SAAU,kCAAkC,CAChD,KAAyB,EAAA;IAEzB,MAAM,MAAM,GACV,CAAC,KAAK,IAAI,2BAA2B,EAAE,IAAI,EAAE;AAC7C,QAAA,2BAA2B;IAC7B,MAAM,OAAO,GAAG,+BAA+B,CAAC,IAAI,CAAC,MAAM,CAAC;IAC5D,OAAO;AACL,QAAA,OAAO,EAAE,EAAE;AACX,QAAA,QAAQ,EAAE,IAAI;AACd,QAAA,WAAW,EAAE,IAAI;AACjB,QAAA,KAAK,EAAE,MAAM;AACb,QAAA,OAAO,EAAE;AACP,cAAE;AACF,cAAE,kEAAkE;AACtE,QAAA,MAAM,EAAE;AACN,cAAE;AACF,cAAE,iEAAiE;KACtE;AACH;AAEA;;;AAGG;SACa,2BAA2B,CACzC,OAAY,EACZ,mBAA2BC,oCAA0B,EAAA;IAErD,MAAM,GAAG,GAAQ,EAAE;IACnB,IAAI,KAAK,GAAG,CAAC;AACb,IAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;QACvC,IAAI,KAAK,GAAG,IAAI,GAAG,gBAAgB,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE;AACvD,QAAA,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAChB,KAAK,IAAI,IAAI;IACf;AACA,IAAA,OAAO,GAAG;AACZ;AAsBM,SAAU,mBAAmB,CAAC,IAAY,EAAA;IAC9C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAACC,4BAAkB,CAAC,EAAE;AACjD,QAAA,MAAM,IAAI,KAAK,CACb,uCAAuCA,4BAAkB,CAAA,CAAA,CAAG,CAC7D;IACH;AACF;AAEA;AACM,SAAU,aAAa,CAAC,IAAsB,EAAA;AAClD,IAAA,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;AAC9B,IAAA,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;AACnD;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.cjs","sources":["../../../src/types/graph.ts"],"sourcesContent":["// src/types/graph.ts\nimport type {\n START,\n StateType,\n UpdateType,\n StateGraph,\n StateGraphArgs,\n StateDefinition,\n CompiledStateGraph,\n BinaryOperatorAggregate,\n} from '@langchain/langgraph';\nimport type { BindToolsInput } from '@langchain/core/language_models/chat_models';\nimport type {\n BaseMessage,\n AIMessageChunk,\n SystemMessage,\n} from '@langchain/core/messages';\nimport type { RunnableConfig, Runnable } from '@langchain/core/runnables';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { GoogleAIToolType } from '@langchain/google-common';\nimport type {\n ToolMap,\n ToolEndEvent,\n GenericTool,\n LCTool,\n ToolApprovalConfig,\n} from '@/types/tools';\nimport type { Providers, Callback, GraphNodeKeys } from '@/common';\nimport type { StandardGraph, MultiAgentGraph } from '@/graphs';\nimport type { ClientOptions } from '@/types/llm';\nimport type {\n RunStep,\n RunStepDeltaEvent,\n MessageDeltaEvent,\n ReasoningDeltaEvent,\n} from '@/types/stream';\nimport type { TokenCounter } from '@/types/run';\n\n/** Interface for bound model with stream and invoke methods */\nexport interface ChatModel {\n stream?: (\n messages: BaseMessage[],\n config?: RunnableConfig\n ) => Promise<AsyncIterable<AIMessageChunk>>;\n invoke: (\n messages: BaseMessage[],\n config?: RunnableConfig\n ) => Promise<AIMessageChunk>;\n}\n\n/** Payload for ON_AGENT_TRANSITION events */\nexport type AgentTransitionEvent = {\n sourceAgentId?: string;\n sourceAgentName?: string;\n destinationAgentId: string;\n destinationAgentName: string;\n edgeType: string; // 'handoff' | 'transfer' | 'sequence'\n timestamp: number;\n /** When true, this event signals handoff completion (child → parent return) */\n isCompletion?: boolean;\n /** Duration of child agent execution in milliseconds (only on completion events) */\n durationMs?: number;\n /** Length of child agent result text in characters (only on completion events) */\n resultLength?: number;\n};\n\nexport type GraphNode = GraphNodeKeys | typeof START;\nexport type ClientCallback<T extends unknown[]> = (\n graph: StandardGraph,\n ...args: T\n) => void;\n\nexport type ClientCallbacks = {\n [Callback.TOOL_ERROR]?: ClientCallback<[Error, string]>;\n [Callback.TOOL_START]?: ClientCallback<unknown[]>;\n [Callback.TOOL_END]?: ClientCallback<unknown[]>;\n};\n\nexport type SystemCallbacks = {\n [K in keyof ClientCallbacks]: ClientCallbacks[K] extends ClientCallback<\n infer Args\n >\n ? (...args: Args) => void\n : never;\n};\n\nexport type BaseGraphState = {\n messages: BaseMessage[];\n /**\n * Structured response when using structured output mode.\n * Contains the validated JSON response conforming to the configured schema.\n */\n structuredResponse?: Record<string, unknown>;\n};\n\nexport type MultiAgentGraphState = BaseGraphState & {\n agentMessages?: BaseMessage[];\n};\n\nexport type IState = BaseGraphState;\n\nexport interface EventHandler {\n handle(\n event: string,\n data:\n | StreamEventData\n | ModelEndData\n | RunStep\n | RunStepDeltaEvent\n | MessageDeltaEvent\n | ReasoningDeltaEvent\n | { result: ToolEndEvent },\n metadata?: Record<string, unknown>,\n graph?: StandardGraph | MultiAgentGraph\n ): void | Promise<void>;\n}\n\nexport type GraphStateChannels<T extends BaseGraphState> =\n StateGraphArgs<T>['channels'];\n\nexport type Workflow<\n T extends BaseGraphState = BaseGraphState,\n U extends Partial<T> = Partial<T>,\n N extends string = string,\n> = StateGraph<T, U, N>;\n\nexport type CompiledWorkflow<\n T extends BaseGraphState = BaseGraphState,\n U extends Partial<T> = Partial<T>,\n N extends string = string,\n> = CompiledStateGraph<T, U, N>;\n\nexport type CompiledStateWorkflow = CompiledStateGraph<\n StateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n UpdateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n string,\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n StateDefinition\n>;\n\nexport type CompiledMultiAgentWorkflow = CompiledStateGraph<\n StateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n UpdateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n string,\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n StateDefinition\n>;\n\nexport type CompiledAgentWorfklow = CompiledStateGraph<\n {\n messages: BaseMessage[];\n },\n {\n messages?: BaseMessage[] | undefined;\n },\n '__start__' | `agent=${string}` | `tools=${string}`,\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n StateDefinition,\n {\n [x: `agent=${string}`]: Partial<BaseGraphState>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: `tools=${string}`]: any;\n }\n>;\n\nexport type SystemRunnable =\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined;\n\n/**\n * Optional compile options passed to workflow.compile().\n * These are intentionally untyped to avoid coupling to library internals.\n */\nexport type CompileOptions = {\n // A checkpointer instance (e.g., MemorySaver, SQL saver)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n checkpointer?: any;\n interruptBefore?: string[];\n interruptAfter?: string[];\n /**\n * Human-in-the-loop tool approval configuration.\n * When set, tools matching the policy will trigger an interrupt()\n * before execution, pausing the graph for human approval.\n * Requires a checkpointer to be set for interrupt/resume to work.\n */\n toolApprovalConfig?: ToolApprovalConfig;\n};\n\nexport type EventStreamCallbackHandlerInput =\n Parameters<CompiledWorkflow['streamEvents']>[2] extends Omit<\n infer T,\n 'autoClose'\n >\n ? T\n : never;\n\nexport type StreamChunk =\n | (ChatGenerationChunk & {\n message: AIMessageChunk;\n })\n | AIMessageChunk;\n\n/**\n * Data associated with a StreamEvent.\n */\nexport type StreamEventData = {\n /**\n * The input passed to the runnable that generated the event.\n * Inputs will sometimes be available at the *START* of the runnable, and\n * sometimes at the *END* of the runnable.\n * If a runnable is able to stream its inputs, then its input by definition\n * won't be known until the *END* of the runnable when it has finished streaming\n * its inputs.\n */\n input?: unknown;\n /**\n * The output of the runnable that generated the event.\n * Outputs will only be available at the *END* of the runnable.\n * For most runnables, this field can be inferred from the `chunk` field,\n * though there might be some exceptions for special cased runnables (e.g., like\n * chat models), which may return more information.\n */\n output?: unknown;\n /**\n * A streaming chunk from the output that generated the event.\n * chunks support addition in general, and adding them up should result\n * in the output of the runnable that generated the event.\n */\n chunk?: StreamChunk;\n /**\n * Runnable config for invoking other runnables within handlers.\n */\n config?: RunnableConfig;\n /**\n * Custom result from the runnable that generated the event.\n */\n result?: unknown;\n /**\n * Custom field to indicate the event was manually emitted, and may have been handled already\n */\n emitted?: boolean;\n};\n\n/**\n * A streaming event.\n *\n * Schema of a streaming event which is produced from the streamEvents method.\n */\nexport type StreamEvent = {\n /**\n * Event names are of the format: on_[runnable_type]_(start|stream|end).\n *\n * Runnable types are one of:\n * - llm - used by non chat models\n * - chat_model - used by chat models\n * - prompt -- e.g., ChatPromptTemplate\n * - tool -- LangChain tools\n * - chain - most Runnables are of this type\n *\n * Further, the events are categorized as one of:\n * - start - when the runnable starts\n * - stream - when the runnable is streaming\n * - end - when the runnable ends\n *\n * start, stream and end are associated with slightly different `data` payload.\n *\n * Please see the documentation for `EventData` for more details.\n */\n event: string;\n /** The name of the runnable that generated the event. */\n name: string;\n /**\n * An randomly generated ID to keep track of the execution of the given runnable.\n *\n * Each child runnable that gets invoked as part of the execution of a parent runnable\n * is assigned its own unique ID.\n */\n run_id: string;\n /**\n * Tags associated with the runnable that generated this event.\n * Tags are always inherited from parent runnables.\n */\n tags?: string[];\n /** Metadata associated with the runnable that generated this event. */\n metadata: Record<string, unknown>;\n /**\n * Event data.\n *\n * The contents of the event data depend on the event type.\n */\n data: StreamEventData;\n};\n\nexport type GraphConfig = {\n provider: string;\n thread_id?: string;\n run_id?: string;\n};\n\nexport type PartMetadata = {\n progress?: number;\n asset_pointer?: string;\n status?: string;\n action?: boolean;\n output?: string;\n};\n\nexport type ModelEndData =\n | (StreamEventData & { output: AIMessageChunk | undefined })\n | undefined;\nexport type GraphTools = GenericTool[] | BindToolsInput[] | GoogleAIToolType[];\nexport type StandardGraphInput = {\n runId?: string;\n signal?: AbortSignal;\n agents: AgentInputs[];\n tokenCounter?: TokenCounter;\n indexTokenCountMap?: Record<string, number>;\n};\n\n/**\n * Configuration for an approval gate placed on a sequence edge.\n * When present, the graph inserts an approval gate node between the source\n * and destination agents. The gate ALWAYS fires (regardless of ExecutionContext)\n * and calls interrupt() to pause the graph for human approval.\n */\nexport type ApprovalGateConfig = {\n /** Unique identifier for this gate (used as node ID suffix) */\n gateId: string;\n /**\n * Approval channel — where the approval UI is rendered.\n * - 'chat': SSE-based chat UI (default)\n * - 'outlook': MS Graph Actionable Messages\n * - 'telegram': Telegram Bot inline keyboard\n */\n channel?: 'chat' | 'outlook' | 'telegram';\n /** Optional human-readable prompt shown to the approver */\n prompt?: string;\n /** Optional approver identifier (e.g., email, user ID) */\n approver?: string;\n /** Timeout in ms before the gate auto-expires (default: 5 minutes) */\n timeoutMs?: number;\n /** What to do on denial: 'stop' ends the graph, 'skip' skips the destination agent */\n onDeny?: 'stop' | 'skip';\n};\n\nexport type GraphEdge = {\n /** Agent ID, use a list for multiple sources */\n from: string | string[];\n /** Agent ID, use a list for multiple destinations */\n to: string | string[];\n description?: string;\n /** Can return boolean or specific destination(s) */\n condition?: (state: BaseGraphState) => boolean | string | string[];\n /**\n * EdgeType.HANDOFF — true agent handoff, parent calls child inline and gets result back.\n * EdgeType.TRANSFER — one-way transfer, parent exits and child takes over.\n * EdgeType.SEQUENCE — fixed graph edges for sequential/parallel transitions.\n */\n edgeType?: import('@/common').EdgeType;\n /**\n * For sequence edges: Optional prompt to add when transitioning through this edge.\n * String prompts can include variables like {results} which will be replaced with\n * messages from startIndex onwards. When {results} is used, excludeResults defaults to true.\n *\n * For transfer edges: Description for the input parameter that the transfer tool accepts,\n * allowing the supervisor to pass specific instructions/context to the transferred agent.\n */\n prompt?:\n | string\n | ((\n messages: BaseMessage[],\n runStartIndex: number\n ) => string | Promise<string> | undefined);\n /**\n * When true, excludes messages from startIndex when adding prompt.\n * Automatically set to true when {results} variable is used in prompt.\n */\n excludeResults?: boolean;\n /**\n * For transfer edges: Customizes the parameter name for the transfer input.\n * Defaults to \"instructions\" if not specified.\n * Only applies when prompt is provided for transfer edges.\n *\n * For handoff edges: Customizes the parameter name for the handoff instruction input.\n */\n promptKey?: string;\n /**\n * For handoff edges: Maximum characters for the result returned to the parent.\n * Uses head/tail truncation (60/40 split) to preserve key findings and conclusions.\n * Defaults to DEFAULT_HANDOFF_MAX_RESULT_CHARS (32768 chars, ~8192 tokens).\n */\n maxResultChars?: number;\n /**\n * Approval gate configuration for sequence edges.\n * When set, inserts an approval gate node between source and destination.\n * The gate ALWAYS fires regardless of ExecutionContext (unlike tool approval).\n */\n approvalGate?: ApprovalGateConfig;\n};\n\nexport type MultiAgentGraphInput = StandardGraphInput & {\n edges: GraphEdge[];\n /**\n * When set, the graph routes START to this agent instead of the default starting nodes.\n * Used for multi-turn resumption: the caller reads `lastActiveAgentId` from the\n * previous turn's metadata and passes it here so follow-up messages route to the\n * agent that last handled the conversation.\n *\n * If the agent ID is invalid (not in the graph), falls back to default starting nodes.\n */\n resumeFromAgentId?: string;\n};\n\n/**\n * Structured output mode determines how the agent returns structured data.\n * - 'tool': Uses tool calling to return structured output (works with all tool-calling models)\n * - 'provider': Uses provider-native structured output via LangChain's jsonMode (OpenAI, Anthropic, etc.)\n * - 'native': Uses provider's constrained decoding API directly for guaranteed schema compliance\n * (Anthropic output_config.format, OpenAI response_format.json_schema). Falls back to 'tool' for unsupported providers.\n * - 'auto': Automatically selects the best strategy — 'native' for supported providers, 'tool' for others\n */\nexport type StructuredOutputMode = 'tool' | 'provider' | 'native' | 'auto';\n\n/**\n * Resolved method used internally after mode resolution.\n * Maps to LangChain's withStructuredOutput method parameter plus our native path.\n */\nexport type ResolvedStructuredOutputMethod =\n | 'functionCalling'\n | 'jsonMode'\n | 'jsonSchema'\n | 'native'\n | undefined;\n\n/**\n * Error thrown when the model refuses to produce structured output due to safety policies.\n */\nexport class StructuredOutputRefusalError extends Error {\n constructor(public refusalText: string) {\n super(`Model refused to produce structured output: ${refusalText}`);\n this.name = 'StructuredOutputRefusalError';\n }\n}\n\n/**\n * Error thrown when the structured output response was truncated due to max_tokens.\n */\nexport class StructuredOutputTruncatedError extends Error {\n constructor(public stopReason: string) {\n super(\n `Structured output was truncated (stop_reason: ${stopReason}). ` +\n 'Increase max_tokens to allow the full JSON response to be generated.'\n );\n this.name = 'StructuredOutputTruncatedError';\n }\n}\n\n/**\n * Configuration for structured JSON output from agents.\n * When configured, the agent will return a validated JSON response\n * instead of streaming text.\n */\nexport interface StructuredOutputConfig {\n /**\n * JSON Schema defining the output structure.\n * The model will be forced to return data conforming to this schema.\n */\n schema: Record<string, unknown>;\n /**\n * Name for the structured output format (used in tool mode).\n * @default 'StructuredResponse'\n */\n name?: string;\n /**\n * Description of what the structured output represents.\n * Helps the model understand the expected format.\n */\n description?: string;\n /**\n * Output mode strategy.\n * @default 'auto'\n */\n mode?: StructuredOutputMode;\n /**\n * Enable strict schema validation.\n * When true, the response must exactly match the schema.\n * @default true\n */\n strict?: boolean;\n /**\n * Error handling configuration.\n * - true: Auto-retry on validation errors (default)\n * - false: Throw error on validation failure\n * - string: Custom error message for retry\n */\n handleErrors?: boolean | string;\n /**\n * Maximum number of retry attempts on validation failure.\n * @default 2\n */\n maxRetries?: number;\n /**\n * Include the raw AI message along with structured response.\n * Useful for debugging.\n * @default false\n */\n includeRaw?: boolean;\n}\n\n/**\n * Database/API structured output format (snake_case with enabled flag).\n * This matches the format stored in MongoDB and sent from frontends.\n */\nexport interface StructuredOutputInput {\n /** Whether structured output is enabled */\n enabled?: boolean;\n /** JSON Schema defining the expected response structure */\n schema?: Record<string, unknown>;\n /** Name identifier for the structured output */\n name?: string;\n /** Description of what the structured output represents */\n description?: string;\n /** Mode for structured output: 'tool' | 'provider' | 'native' | 'auto' */\n mode?: StructuredOutputMode;\n /** Whether to enforce strict schema validation */\n strict?: boolean;\n}\n\n/**\n * Trigger strategy for when summarization should activate.\n * - 'contextPercentage': Trigger when context utilization exceeds a threshold percentage\n * - 'messageCount': Trigger when pruned message count exceeds a threshold\n * - 'tokenThreshold': Trigger when total token count exceeds a raw threshold\n */\nexport type SummarizationTriggerType =\n | 'contextPercentage'\n | 'messageCount'\n | 'tokenThreshold';\n\n/**\n * Configuration for summarization behavior within the agent pipeline.\n * All fields are optional — sensible defaults are provided via constants.\n *\n * @see SUMMARIZATION_CONTEXT_THRESHOLD, SUMMARIZATION_RESERVE_RATIO, PRUNING_EMA_ALPHA\n */\nexport interface SummarizationConfig {\n /**\n * Strategy for when summarization triggers.\n * @default 'contextPercentage'\n */\n triggerType?: SummarizationTriggerType;\n\n /**\n * Threshold value interpreted based on triggerType:\n * - contextPercentage: 0-100 (percentage of context window)\n * - messageCount: absolute count of messages pruned\n * - tokenThreshold: absolute token count\n * @default 80 (for contextPercentage)\n */\n triggerThreshold?: number;\n\n /**\n * Fraction of context window (0-1) reserved for recent messages.\n * Prevents over-pruning by ensuring at least this fraction of the\n * context budget is preserved as recent conversation history.\n * @default 0.3\n */\n reserveRatio?: number;\n\n /**\n * Whether context pruning is enabled (can be disabled for debugging).\n * @default true\n */\n contextPruning?: boolean;\n\n /**\n * Initial summary text to seed across runs.\n * Different from persistedSummary: this is provided by the caller as a\n * cross-conversation seed (e.g., agent personality or recurring context),\n * while persistedSummary is loaded from the conversation's own history.\n */\n initialSummary?: string;\n}\n\n/**\n * Runtime state for EMA-based pruning calibration.\n * Maintained across iterations within a single run to smooth pruning decisions.\n */\nexport interface PruneCalibrationState {\n /** Current EMA calibration ratio */\n ratio: number;\n /** Number of calibration updates applied */\n iterations: number;\n}\n\n/**\n * Lightweight file metadata entry for conversation-level file awareness.\n * Contains only IDs and names — NOT full content — so the agent always knows\n * what files exist in the conversation even after compaction pushes old messages\n * behind the summary window. The agent can retrieve full content on-demand\n * via file_search (RAG) or content_tool read (by contentId).\n */\nexport interface FileManifestEntry {\n /** Unique file identifier (e.g., MongoDB ObjectId or UUID) */\n fileId: string;\n /** Original filename (e.g., \"quarterly-report.pdf\") */\n filename: string;\n /** Content identifier for on-demand retrieval via content_tool read */\n contentId?: string;\n /** File source (e.g., \"local\", \"sharepoint\", \"onedrive\") */\n source?: string;\n /** Index of the message that introduced this file (0-based in the original message array) */\n messageIndex?: number;\n}\n\nexport interface AgentInputs {\n agentId: string;\n /** Human-readable name for the agent (used in handoff context). Defaults to agentId if not provided. */\n name?: string;\n /** Description of what this agent does (used to enrich handoff tool descriptions). */\n description?: string;\n toolEnd?: boolean;\n toolMap?: ToolMap;\n tools?: GraphTools;\n provider: Providers;\n instructions?: string;\n streamBuffer?: number;\n maxContextTokens?: number;\n clientOptions?: ClientOptions;\n additional_instructions?: string;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n /** Format content blocks as strings (for legacy compatibility i.e. Ollama/Azure Serverless) */\n useLegacyContent?: boolean;\n /**\n * Tool definitions for all tools, including deferred and programmatic.\n * Used for tool search and programmatic tool calling.\n * Maps tool name to LCTool definition.\n */\n toolRegistry?: Map<string, LCTool>;\n /**\n * Dynamic context that changes per-request (e.g., current time, user info).\n * This is injected as a user message rather than system prompt to preserve cache.\n * Keeping this separate from instructions ensures the system message stays static\n * and can be cached by Bedrock/Anthropic prompt caching.\n */\n dynamicContext?: string;\n /**\n * Structured output configuration (camelCase).\n * When set, disables streaming and returns a validated JSON response\n * conforming to the specified schema.\n */\n structuredOutput?: StructuredOutputConfig;\n /**\n * Structured output configuration (snake_case - database/API format).\n * Alternative to structuredOutput for compatibility with MongoDB/frontend.\n * Uses an `enabled` flag to control activation.\n * @deprecated Use structuredOutput instead when possible\n */\n structured_output?: StructuredOutputInput;\n /**\n * Serializable tool definitions for event-driven execution.\n * When provided, ToolNode operates in event-driven mode, dispatching\n * ON_TOOL_EXECUTE events instead of invoking tools directly.\n */\n toolDefinitions?: LCTool[];\n /**\n * Tool names discovered from previous conversation history.\n * These tools will be pre-marked as discovered so they're included\n * in tool binding without requiring tool_search.\n */\n discoveredTools?: string[];\n /**\n * Optional callback for summarizing messages that were pruned from context.\n * When provided, discarded messages are summarized by the caller (e.g., Ranger)\n * using a cheap LLM call, and the summary is prepended to the context.\n */\n summarizeCallback?: (\n messagesToRefine: import('@langchain/core/messages').BaseMessage[]\n ) => Promise<string | undefined>;\n /**\n * Pre-existing summary text loaded from persistent storage (MongoDB/Redis).\n * When provided, this summary is injected into the initial message context\n * so the agent has prior conversation history even on new turns.\n * Set by Ranger's SummaryStore when resuming a conversation.\n */\n persistedSummary?: string;\n /**\n * Summarization configuration controlling trigger strategy, reserve ratio,\n * and EMA calibration for pruning. When omitted, sensible defaults apply.\n * @see SummarizationConfig\n */\n summarizationConfig?: SummarizationConfig;\n /**\n * Lightweight file manifest for the conversation.\n * Contains file IDs, names, and metadata — NOT full content.\n *\n * Used by the compaction engine to inject a [Conversation Files] block\n * into the windowed view, ensuring the LLM always knows what files exist\n * even when old messages (with full file content) are behind the summary.\n *\n * The agent can retrieve full content on-demand via:\n * - file_search (RAG semantic search over embedded files)\n * - content_tool read (by contentId for exact file retrieval)\n *\n * Built by the orchestrator (e.g., Ranger) from message_file_map\n * and metadata.context_files across all conversation messages.\n */\n fileManifest?: FileManifestEntry[];\n}\n"],"names":[],"mappings":";;AAidA;;AAEG;AACG,MAAO,4BAA6B,SAAQ,KAAK,CAAA;AAClC,IAAA,WAAA;AAAnB,IAAA,WAAA,CAAmB,WAAmB,EAAA;AACpC,QAAA,KAAK,CAAC,CAAA,4CAAA,EAA+C,WAAW,CAAA,CAAE,CAAC;QADlD,IAAA,CAAA,WAAW,GAAX,WAAW;AAE5B,QAAA,IAAI,CAAC,IAAI,GAAG,8BAA8B;IAC5C;AACD;AAED;;AAEG;AACG,MAAO,8BAA+B,SAAQ,KAAK,CAAA;AACpC,IAAA,UAAA;AAAnB,IAAA,WAAA,CAAmB,UAAkB,EAAA;QACnC,KAAK,CACH,CAAA,8CAAA,EAAiD,UAAU,CAAA,GAAA,CAAK;AAC9D,YAAA,sEAAsE,CACzE;QAJgB,IAAA,CAAA,UAAU,GAAV,UAAU;AAK3B,QAAA,IAAI,CAAC,IAAI,GAAG,gCAAgC;IAC9C;AACD;;;;;"}
|
|
1
|
+
{"version":3,"file":"graph.cjs","sources":["../../../src/types/graph.ts"],"sourcesContent":["// src/types/graph.ts\nimport type {\n START,\n StateType,\n UpdateType,\n StateGraph,\n StateGraphArgs,\n StateDefinition,\n CompiledStateGraph,\n BinaryOperatorAggregate,\n} from '@langchain/langgraph';\nimport type { BindToolsInput } from '@langchain/core/language_models/chat_models';\nimport type {\n BaseMessage,\n AIMessageChunk,\n SystemMessage,\n} from '@langchain/core/messages';\nimport type { RunnableConfig, Runnable } from '@langchain/core/runnables';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { GoogleAIToolType } from '@langchain/google-common';\nimport type {\n ToolMap,\n ToolEndEvent,\n GenericTool,\n LCTool,\n ToolApprovalConfig,\n} from '@/types/tools';\nimport type { Providers, Callback, GraphNodeKeys } from '@/common';\nimport type { StandardGraph, MultiAgentGraph } from '@/graphs';\nimport type { ClientOptions } from '@/types/llm';\nimport type {\n RunStep,\n RunStepDeltaEvent,\n MessageDeltaEvent,\n ReasoningDeltaEvent,\n} from '@/types/stream';\nimport type { TokenCounter } from '@/types/run';\n\n/** Interface for bound model with stream and invoke methods */\nexport interface ChatModel {\n stream?: (\n messages: BaseMessage[],\n config?: RunnableConfig\n ) => Promise<AsyncIterable<AIMessageChunk>>;\n invoke: (\n messages: BaseMessage[],\n config?: RunnableConfig\n ) => Promise<AIMessageChunk>;\n}\n\n/** Payload for ON_AGENT_TRANSITION events */\nexport type AgentTransitionEvent = {\n sourceAgentId?: string;\n sourceAgentName?: string;\n destinationAgentId: string;\n destinationAgentName: string;\n edgeType: string; // 'handoff' | 'transfer' | 'sequence'\n timestamp: number;\n /** When true, this event signals handoff completion (child → parent return) */\n isCompletion?: boolean;\n /** Duration of child agent execution in milliseconds (only on completion events) */\n durationMs?: number;\n /** Length of child agent result text in characters (only on completion events) */\n resultLength?: number;\n};\n\nexport type GraphNode = GraphNodeKeys | typeof START;\nexport type ClientCallback<T extends unknown[]> = (\n graph: StandardGraph,\n ...args: T\n) => void;\n\nexport type ClientCallbacks = {\n [Callback.TOOL_ERROR]?: ClientCallback<[Error, string]>;\n [Callback.TOOL_START]?: ClientCallback<unknown[]>;\n [Callback.TOOL_END]?: ClientCallback<unknown[]>;\n};\n\nexport type SystemCallbacks = {\n [K in keyof ClientCallbacks]: ClientCallbacks[K] extends ClientCallback<\n infer Args\n >\n ? (...args: Args) => void\n : never;\n};\n\nexport type BaseGraphState = {\n messages: BaseMessage[];\n /**\n * Structured response when using structured output mode.\n * Contains the validated JSON response conforming to the configured schema.\n */\n structuredResponse?: Record<string, unknown>;\n};\n\nexport type MultiAgentGraphState = BaseGraphState & {\n agentMessages?: BaseMessage[];\n};\n\nexport type IState = BaseGraphState;\n\nexport interface EventHandler {\n handle(\n event: string,\n data:\n | StreamEventData\n | ModelEndData\n | RunStep\n | RunStepDeltaEvent\n | MessageDeltaEvent\n | ReasoningDeltaEvent\n | { result: ToolEndEvent },\n metadata?: Record<string, unknown>,\n graph?: StandardGraph | MultiAgentGraph\n ): void | Promise<void>;\n}\n\nexport type GraphStateChannels<T extends BaseGraphState> =\n StateGraphArgs<T>['channels'];\n\nexport type Workflow<\n T extends BaseGraphState = BaseGraphState,\n U extends Partial<T> = Partial<T>,\n N extends string = string,\n> = StateGraph<T, U, N>;\n\nexport type CompiledWorkflow<\n T extends BaseGraphState = BaseGraphState,\n U extends Partial<T> = Partial<T>,\n N extends string = string,\n> = CompiledStateGraph<T, U, N>;\n\nexport type CompiledStateWorkflow = CompiledStateGraph<\n StateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n UpdateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n string,\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n StateDefinition\n>;\n\nexport type CompiledMultiAgentWorkflow = CompiledStateGraph<\n StateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n UpdateType<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n }>,\n string,\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n agentMessages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n StateDefinition\n>;\n\nexport type CompiledAgentWorfklow = CompiledStateGraph<\n {\n messages: BaseMessage[];\n },\n {\n messages?: BaseMessage[] | undefined;\n },\n '__start__' | `agent=${string}` | `tools=${string}`,\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n {\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n },\n StateDefinition,\n {\n [x: `agent=${string}`]: Partial<BaseGraphState>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [x: `tools=${string}`]: any;\n }\n>;\n\nexport type SystemRunnable =\n | Runnable<\n BaseMessage[],\n (BaseMessage | SystemMessage)[],\n RunnableConfig<Record<string, unknown>>\n >\n | undefined;\n\n/**\n * Optional compile options passed to workflow.compile().\n * These are intentionally untyped to avoid coupling to library internals.\n */\nexport type CompileOptions = {\n // A checkpointer instance (e.g., MemorySaver, SQL saver)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n checkpointer?: any;\n interruptBefore?: string[];\n interruptAfter?: string[];\n /**\n * Human-in-the-loop tool approval configuration.\n * When set, tools matching the policy will trigger an interrupt()\n * before execution, pausing the graph for human approval.\n * Requires a checkpointer to be set for interrupt/resume to work.\n */\n toolApprovalConfig?: ToolApprovalConfig;\n};\n\nexport type EventStreamCallbackHandlerInput =\n Parameters<CompiledWorkflow['streamEvents']>[2] extends Omit<\n infer T,\n 'autoClose'\n >\n ? T\n : never;\n\nexport type StreamChunk =\n | (ChatGenerationChunk & {\n message: AIMessageChunk;\n })\n | AIMessageChunk;\n\n/**\n * Data associated with a StreamEvent.\n */\nexport type StreamEventData = {\n /**\n * The input passed to the runnable that generated the event.\n * Inputs will sometimes be available at the *START* of the runnable, and\n * sometimes at the *END* of the runnable.\n * If a runnable is able to stream its inputs, then its input by definition\n * won't be known until the *END* of the runnable when it has finished streaming\n * its inputs.\n */\n input?: unknown;\n /**\n * The output of the runnable that generated the event.\n * Outputs will only be available at the *END* of the runnable.\n * For most runnables, this field can be inferred from the `chunk` field,\n * though there might be some exceptions for special cased runnables (e.g., like\n * chat models), which may return more information.\n */\n output?: unknown;\n /**\n * A streaming chunk from the output that generated the event.\n * chunks support addition in general, and adding them up should result\n * in the output of the runnable that generated the event.\n */\n chunk?: StreamChunk;\n /**\n * Runnable config for invoking other runnables within handlers.\n */\n config?: RunnableConfig;\n /**\n * Custom result from the runnable that generated the event.\n */\n result?: unknown;\n /**\n * Custom field to indicate the event was manually emitted, and may have been handled already\n */\n emitted?: boolean;\n};\n\n/**\n * A streaming event.\n *\n * Schema of a streaming event which is produced from the streamEvents method.\n */\nexport type StreamEvent = {\n /**\n * Event names are of the format: on_[runnable_type]_(start|stream|end).\n *\n * Runnable types are one of:\n * - llm - used by non chat models\n * - chat_model - used by chat models\n * - prompt -- e.g., ChatPromptTemplate\n * - tool -- LangChain tools\n * - chain - most Runnables are of this type\n *\n * Further, the events are categorized as one of:\n * - start - when the runnable starts\n * - stream - when the runnable is streaming\n * - end - when the runnable ends\n *\n * start, stream and end are associated with slightly different `data` payload.\n *\n * Please see the documentation for `EventData` for more details.\n */\n event: string;\n /** The name of the runnable that generated the event. */\n name: string;\n /**\n * An randomly generated ID to keep track of the execution of the given runnable.\n *\n * Each child runnable that gets invoked as part of the execution of a parent runnable\n * is assigned its own unique ID.\n */\n run_id: string;\n /**\n * Tags associated with the runnable that generated this event.\n * Tags are always inherited from parent runnables.\n */\n tags?: string[];\n /** Metadata associated with the runnable that generated this event. */\n metadata: Record<string, unknown>;\n /**\n * Event data.\n *\n * The contents of the event data depend on the event type.\n */\n data: StreamEventData;\n};\n\nexport type GraphConfig = {\n provider: string;\n thread_id?: string;\n run_id?: string;\n};\n\nexport type PartMetadata = {\n progress?: number;\n asset_pointer?: string;\n status?: string;\n action?: boolean;\n output?: string;\n};\n\nexport type ModelEndData =\n | (StreamEventData & { output: AIMessageChunk | undefined })\n | undefined;\nexport type GraphTools = GenericTool[] | BindToolsInput[] | GoogleAIToolType[];\nexport type StandardGraphInput = {\n runId?: string;\n signal?: AbortSignal;\n agents: AgentInputs[];\n tokenCounter?: TokenCounter;\n indexTokenCountMap?: Record<string, number>;\n};\n\n/**\n * Configuration for an approval gate placed on a sequence edge.\n * When present, the graph inserts an approval gate node between the source\n * and destination agents. The gate ALWAYS fires (regardless of ExecutionContext)\n * and calls interrupt() to pause the graph for human approval.\n */\nexport type ApprovalGateConfig = {\n /** Unique identifier for this gate (used as node ID suffix) */\n gateId: string;\n /**\n * Approval channel — where the approval UI is rendered.\n * - 'chat': SSE-based chat UI (default)\n * - 'outlook': MS Graph Actionable Messages\n * - 'telegram': Telegram Bot inline keyboard\n */\n channel?: 'chat' | 'outlook' | 'telegram';\n /** Optional human-readable prompt shown to the approver */\n prompt?: string;\n /** Optional approver identifier (e.g., email, user ID) */\n approver?: string;\n /** Timeout in ms before the gate auto-expires (default: 5 minutes) */\n timeoutMs?: number;\n /** What to do on denial: 'stop' ends the graph, 'skip' skips the destination agent */\n onDeny?: 'stop' | 'skip';\n};\n\nexport type GraphEdge = {\n /** Agent ID, use a list for multiple sources */\n from: string | string[];\n /** Agent ID, use a list for multiple destinations */\n to: string | string[];\n description?: string;\n /** Can return boolean or specific destination(s) */\n condition?: (state: BaseGraphState) => boolean | string | string[];\n /**\n * EdgeType.HANDOFF — true agent handoff, parent calls child inline and gets result back.\n * EdgeType.TRANSFER — one-way transfer, parent exits and child takes over.\n * EdgeType.SEQUENCE — fixed graph edges for sequential/parallel transitions.\n */\n edgeType?: import('@/common').EdgeType;\n /**\n * For sequence edges: Optional prompt to add when transitioning through this edge.\n * String prompts can include variables like {results} which will be replaced with\n * messages from startIndex onwards. When {results} is used, excludeResults defaults to true.\n *\n * For transfer edges: Description for the input parameter that the transfer tool accepts,\n * allowing the supervisor to pass specific instructions/context to the transferred agent.\n */\n prompt?:\n | string\n | ((\n messages: BaseMessage[],\n runStartIndex: number\n ) => string | Promise<string> | undefined);\n /**\n * When true, excludes messages from startIndex when adding prompt.\n * Automatically set to true when {results} variable is used in prompt.\n */\n excludeResults?: boolean;\n /**\n * For transfer edges: Customizes the parameter name for the transfer input.\n * Defaults to \"instructions\" if not specified.\n * Only applies when prompt is provided for transfer edges.\n *\n * For handoff edges: Customizes the parameter name for the handoff instruction input.\n */\n promptKey?: string;\n /**\n * For handoff edges: Maximum characters for the result returned to the parent.\n * Uses head/tail truncation (60/40 split) to preserve key findings and conclusions.\n * Defaults to DEFAULT_HANDOFF_MAX_RESULT_CHARS (32768 chars, ~8192 tokens).\n */\n maxResultChars?: number;\n /**\n * For handoff edges: When true, the child agent receives the full parent\n * conversation history plus the orchestrator's instructions appended.\n * When false (default), the child only receives the orchestrator's scoped\n * instructions — isolated from the parent conversation.\n */\n passthrough?: boolean;\n /**\n * Approval gate configuration for sequence edges.\n * When set, inserts an approval gate node between source and destination.\n * The gate ALWAYS fires regardless of ExecutionContext (unlike tool approval).\n */\n approvalGate?: ApprovalGateConfig;\n};\n\nexport type MultiAgentGraphInput = StandardGraphInput & {\n edges: GraphEdge[];\n /**\n * When set, the graph routes START to this agent instead of the default starting nodes.\n * Used for multi-turn resumption: the caller reads `lastActiveAgentId` from the\n * previous turn's metadata and passes it here so follow-up messages route to the\n * agent that last handled the conversation.\n *\n * If the agent ID is invalid (not in the graph), falls back to default starting nodes.\n */\n resumeFromAgentId?: string;\n};\n\n/**\n * Structured output mode determines how the agent returns structured data.\n * - 'tool': Uses tool calling to return structured output (works with all tool-calling models)\n * - 'provider': Uses provider-native structured output via LangChain's jsonMode (OpenAI, Anthropic, etc.)\n * - 'native': Uses provider's constrained decoding API directly for guaranteed schema compliance\n * (Anthropic output_config.format, OpenAI response_format.json_schema). Falls back to 'tool' for unsupported providers.\n * - 'auto': Automatically selects the best strategy — 'native' for supported providers, 'tool' for others\n */\nexport type StructuredOutputMode = 'tool' | 'provider' | 'native' | 'auto';\n\n/**\n * Resolved method used internally after mode resolution.\n * Maps to LangChain's withStructuredOutput method parameter plus our native path.\n */\nexport type ResolvedStructuredOutputMethod =\n | 'functionCalling'\n | 'jsonMode'\n | 'jsonSchema'\n | 'native'\n | undefined;\n\n/**\n * Error thrown when the model refuses to produce structured output due to safety policies.\n */\nexport class StructuredOutputRefusalError extends Error {\n constructor(public refusalText: string) {\n super(`Model refused to produce structured output: ${refusalText}`);\n this.name = 'StructuredOutputRefusalError';\n }\n}\n\n/**\n * Error thrown when the structured output response was truncated due to max_tokens.\n */\nexport class StructuredOutputTruncatedError extends Error {\n constructor(public stopReason: string) {\n super(\n `Structured output was truncated (stop_reason: ${stopReason}). ` +\n 'Increase max_tokens to allow the full JSON response to be generated.'\n );\n this.name = 'StructuredOutputTruncatedError';\n }\n}\n\n/**\n * Configuration for structured JSON output from agents.\n * When configured, the agent will return a validated JSON response\n * instead of streaming text.\n */\nexport interface StructuredOutputConfig {\n /**\n * JSON Schema defining the output structure.\n * The model will be forced to return data conforming to this schema.\n */\n schema: Record<string, unknown>;\n /**\n * Name for the structured output format (used in tool mode).\n * @default 'StructuredResponse'\n */\n name?: string;\n /**\n * Description of what the structured output represents.\n * Helps the model understand the expected format.\n */\n description?: string;\n /**\n * Output mode strategy.\n * @default 'auto'\n */\n mode?: StructuredOutputMode;\n /**\n * Enable strict schema validation.\n * When true, the response must exactly match the schema.\n * @default true\n */\n strict?: boolean;\n /**\n * Error handling configuration.\n * - true: Auto-retry on validation errors (default)\n * - false: Throw error on validation failure\n * - string: Custom error message for retry\n */\n handleErrors?: boolean | string;\n /**\n * Maximum number of retry attempts on validation failure.\n * @default 2\n */\n maxRetries?: number;\n /**\n * Include the raw AI message along with structured response.\n * Useful for debugging.\n * @default false\n */\n includeRaw?: boolean;\n}\n\n/**\n * Database/API structured output format (snake_case with enabled flag).\n * This matches the format stored in MongoDB and sent from frontends.\n */\nexport interface StructuredOutputInput {\n /** Whether structured output is enabled */\n enabled?: boolean;\n /** JSON Schema defining the expected response structure */\n schema?: Record<string, unknown>;\n /** Name identifier for the structured output */\n name?: string;\n /** Description of what the structured output represents */\n description?: string;\n /** Mode for structured output: 'tool' | 'provider' | 'native' | 'auto' */\n mode?: StructuredOutputMode;\n /** Whether to enforce strict schema validation */\n strict?: boolean;\n}\n\n/**\n * Trigger strategy for when summarization should activate.\n * - 'contextPercentage': Trigger when context utilization exceeds a threshold percentage\n * - 'messageCount': Trigger when pruned message count exceeds a threshold\n * - 'tokenThreshold': Trigger when total token count exceeds a raw threshold\n */\nexport type SummarizationTriggerType =\n | 'contextPercentage'\n | 'messageCount'\n | 'tokenThreshold';\n\n/**\n * Configuration for summarization behavior within the agent pipeline.\n * All fields are optional — sensible defaults are provided via constants.\n *\n * @see SUMMARIZATION_CONTEXT_THRESHOLD, SUMMARIZATION_RESERVE_RATIO, PRUNING_EMA_ALPHA\n */\nexport interface SummarizationConfig {\n /**\n * Strategy for when summarization triggers.\n * @default 'contextPercentage'\n */\n triggerType?: SummarizationTriggerType;\n\n /**\n * Threshold value interpreted based on triggerType:\n * - contextPercentage: 0-100 (percentage of context window)\n * - messageCount: absolute count of messages pruned\n * - tokenThreshold: absolute token count\n * @default 80 (for contextPercentage)\n */\n triggerThreshold?: number;\n\n /**\n * Fraction of context window (0-1) reserved for recent messages.\n * Prevents over-pruning by ensuring at least this fraction of the\n * context budget is preserved as recent conversation history.\n * @default 0.3\n */\n reserveRatio?: number;\n\n /**\n * Whether context pruning is enabled (can be disabled for debugging).\n * @default true\n */\n contextPruning?: boolean;\n\n /**\n * Initial summary text to seed across runs.\n * Different from persistedSummary: this is provided by the caller as a\n * cross-conversation seed (e.g., agent personality or recurring context),\n * while persistedSummary is loaded from the conversation's own history.\n */\n initialSummary?: string;\n}\n\n/**\n * Runtime state for EMA-based pruning calibration.\n * Maintained across iterations within a single run to smooth pruning decisions.\n */\nexport interface PruneCalibrationState {\n /** Current EMA calibration ratio */\n ratio: number;\n /** Number of calibration updates applied */\n iterations: number;\n}\n\n/**\n * Lightweight file metadata entry for conversation-level file awareness.\n * Contains only IDs and names — NOT full content — so the agent always knows\n * what files exist in the conversation even after compaction pushes old messages\n * behind the summary window. The agent can retrieve full content on-demand\n * via file_search (RAG) or content_tool read (by contentId).\n */\nexport interface FileManifestEntry {\n /** Unique file identifier (e.g., MongoDB ObjectId or UUID) */\n fileId: string;\n /** Original filename (e.g., \"quarterly-report.pdf\") */\n filename: string;\n /** Content identifier for on-demand retrieval via content_tool read */\n contentId?: string;\n /** File source (e.g., \"local\", \"sharepoint\", \"onedrive\") */\n source?: string;\n /** Index of the message that introduced this file (0-based in the original message array) */\n messageIndex?: number;\n}\n\nexport interface AgentInputs {\n agentId: string;\n /** Human-readable name for the agent (used in handoff context). Defaults to agentId if not provided. */\n name?: string;\n /** Description of what this agent does (used to enrich handoff tool descriptions). */\n description?: string;\n toolEnd?: boolean;\n toolMap?: ToolMap;\n tools?: GraphTools;\n provider: Providers;\n instructions?: string;\n streamBuffer?: number;\n maxContextTokens?: number;\n clientOptions?: ClientOptions;\n additional_instructions?: string;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n /** Format content blocks as strings (for legacy compatibility i.e. Ollama/Azure Serverless) */\n useLegacyContent?: boolean;\n /**\n * Tool definitions for all tools, including deferred and programmatic.\n * Used for tool search and programmatic tool calling.\n * Maps tool name to LCTool definition.\n */\n toolRegistry?: Map<string, LCTool>;\n /**\n * Dynamic context that changes per-request (e.g., current time, user info).\n * This is injected as a user message rather than system prompt to preserve cache.\n * Keeping this separate from instructions ensures the system message stays static\n * and can be cached by Bedrock/Anthropic prompt caching.\n */\n dynamicContext?: string;\n /**\n * Structured output configuration (camelCase).\n * When set, disables streaming and returns a validated JSON response\n * conforming to the specified schema.\n */\n structuredOutput?: StructuredOutputConfig;\n /**\n * Structured output configuration (snake_case - database/API format).\n * Alternative to structuredOutput for compatibility with MongoDB/frontend.\n * Uses an `enabled` flag to control activation.\n * @deprecated Use structuredOutput instead when possible\n */\n structured_output?: StructuredOutputInput;\n /**\n * Serializable tool definitions for event-driven execution.\n * When provided, ToolNode operates in event-driven mode, dispatching\n * ON_TOOL_EXECUTE events instead of invoking tools directly.\n */\n toolDefinitions?: LCTool[];\n /**\n * Tool names discovered from previous conversation history.\n * These tools will be pre-marked as discovered so they're included\n * in tool binding without requiring tool_search.\n */\n discoveredTools?: string[];\n /**\n * Optional callback for summarizing messages that were pruned from context.\n * When provided, discarded messages are summarized by the host caller\n * using a cheap LLM call, and the summary is prepended to the context.\n */\n summarizeCallback?: (\n messagesToRefine: import('@langchain/core/messages').BaseMessage[]\n ) => Promise<string | undefined>;\n /**\n * Pre-existing summary text loaded from persistent storage (MongoDB/Redis).\n * When provided, this summary is injected into the initial message context\n * so the agent has prior conversation history even on new turns.\n * Set by the host's summary store when resuming a conversation.\n */\n persistedSummary?: string;\n /**\n * Summarization configuration controlling trigger strategy, reserve ratio,\n * and EMA calibration for pruning. When omitted, sensible defaults apply.\n * @see SummarizationConfig\n */\n summarizationConfig?: SummarizationConfig;\n /**\n * Lightweight file manifest for the conversation.\n * Contains file IDs, names, and metadata — NOT full content.\n *\n * Used by the compaction engine to inject a [Conversation Files] block\n * into the windowed view, ensuring the LLM always knows what files exist\n * even when old messages (with full file content) are behind the summary.\n *\n * The agent can retrieve full content on-demand via:\n * - file_search (RAG semantic search over embedded files)\n * - content_tool read (by contentId for exact file retrieval)\n *\n * Built by the host orchestrator from message_file_map\n * and metadata.context_files across all conversation messages.\n */\n fileManifest?: FileManifestEntry[];\n}\n"],"names":[],"mappings":";;AAwdA;;AAEG;AACG,MAAO,4BAA6B,SAAQ,KAAK,CAAA;AAClC,IAAA,WAAA;AAAnB,IAAA,WAAA,CAAmB,WAAmB,EAAA;AACpC,QAAA,KAAK,CAAC,CAAA,4CAAA,EAA+C,WAAW,CAAA,CAAE,CAAC;QADlD,IAAA,CAAA,WAAW,GAAX,WAAW;AAE5B,QAAA,IAAI,CAAC,IAAI,GAAG,8BAA8B;IAC5C;AACD;AAED;;AAEG;AACG,MAAO,8BAA+B,SAAQ,KAAK,CAAA;AACpC,IAAA,UAAA;AAAnB,IAAA,WAAA,CAAmB,UAAkB,EAAA;QACnC,KAAK,CACH,CAAA,8CAAA,EAAiD,UAAU,CAAA,GAAA,CAAK;AAC9D,YAAA,sEAAsE,CACzE;QAJgB,IAAA,CAAA,UAAU,GAAV,UAAU;AAK3B,QAAA,IAAI,CAAC,IAAI,GAAG,gCAAgC;IAC9C;AACD;;;;;"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var messages = require('@langchain/core/messages');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Child-agent context preparation utilities.
|
|
7
|
+
*
|
|
8
|
+
* When a parent agent invokes a child agent — via handoff, sequence edge,
|
|
9
|
+
* or scoped subgraph — the child cannot just receive `state.messages`
|
|
10
|
+
* verbatim. The parent's conversation contains tool_use/tool_result blocks
|
|
11
|
+
* that are (a) often incompatible with the child's tool registry, and
|
|
12
|
+
* (b) actively harmful to the child's ability to reason cleanly about its
|
|
13
|
+
* own task (noise → schema confusion → malformed tool_use).
|
|
14
|
+
*
|
|
15
|
+
* This module provides the two canonical strategies, extracted from
|
|
16
|
+
* `MultiAgentGraph` so they can be unit-tested in isolation and reused by
|
|
17
|
+
* future sub-agent orchestrators:
|
|
18
|
+
*
|
|
19
|
+
* 1. `prepareHandoffMessages` — "cleaned parent history"
|
|
20
|
+
* Used when the child still needs the orchestrator's context (it's
|
|
21
|
+
* the handoff target). Drops orphaned tool_use, compacts paired
|
|
22
|
+
* tool_use/tool_result into text summaries, and guarantees the tail
|
|
23
|
+
* is a HumanMessage so Bedrock/VertexAI won't reject the conversation
|
|
24
|
+
* with "assistant message prefill" errors.
|
|
25
|
+
*
|
|
26
|
+
* 2. `prepareIsolatedChildMessages` — "fresh session"
|
|
27
|
+
* Used for downstream sequence-node children inside a scoped subgraph.
|
|
28
|
+
* The child sees only the original user request plus a synthetic
|
|
29
|
+
* HumanMessage summarizing the upstream agent's final text output and
|
|
30
|
+
* directing the child to act. Raw upstream tool_use/tool_result blocks
|
|
31
|
+
* are discarded.
|
|
32
|
+
*
|
|
33
|
+
* Both helpers are pure functions over message arrays — no I/O, no
|
|
34
|
+
* LangGraph coupling — so they can be exercised by unit tests with
|
|
35
|
+
* synthetic message fixtures.
|
|
36
|
+
*/
|
|
37
|
+
/* -------------------------------------------------------------------------- */
|
|
38
|
+
/* Prompt template constants (kept outside the functions for reuse/tuning) */
|
|
39
|
+
/* -------------------------------------------------------------------------- */
|
|
40
|
+
/**
|
|
41
|
+
* Prefix injected in front of a trailing AIMessage when we flip it to a
|
|
42
|
+
* HumanMessage to satisfy provider "last message must be user" rules.
|
|
43
|
+
*/
|
|
44
|
+
const HANDOFF_TAIL_CONTEXT_PREFIX = '[Context from orchestrator]: ';
|
|
45
|
+
/**
|
|
46
|
+
* Directive task-framing wrapper for downstream scoped-subgraph children.
|
|
47
|
+
*
|
|
48
|
+
* Design notes — each line is load-bearing:
|
|
49
|
+
* - "Prior step output" names the upstream role without leaking the
|
|
50
|
+
* agent's internal id.
|
|
51
|
+
* - "You MUST now perform..." replaces ambiguity with obligation.
|
|
52
|
+
* - "system instructions" references the agent's stored system prompt
|
|
53
|
+
* as the source of task definition — so operators can tune behavior
|
|
54
|
+
* via data, not code.
|
|
55
|
+
* - The tool-first clause prevents small/fast models from stalling on a
|
|
56
|
+
* text-only acknowledgement when a tool action is expected.
|
|
57
|
+
*/
|
|
58
|
+
function buildIsolatedChildPrompt(upstreamText) {
|
|
59
|
+
return ('## Prior step output\n\n' +
|
|
60
|
+
upstreamText +
|
|
61
|
+
'\n\n---\n\n' +
|
|
62
|
+
'## Your task\n\n' +
|
|
63
|
+
'The previous step in this workflow has completed. You MUST now ' +
|
|
64
|
+
'perform your own task as defined in your system instructions, ' +
|
|
65
|
+
"using the prior step's output as input where relevant.\n\n" +
|
|
66
|
+
'If your task requires calling a tool, call it directly — do not ' +
|
|
67
|
+
'ask for clarification and do not produce a text-only response when ' +
|
|
68
|
+
'a tool action is expected.');
|
|
69
|
+
}
|
|
70
|
+
/* -------------------------------------------------------------------------- */
|
|
71
|
+
/* Internal helpers */
|
|
72
|
+
/* -------------------------------------------------------------------------- */
|
|
73
|
+
/**
|
|
74
|
+
* Extract concatenated text content from an AI message's content field.
|
|
75
|
+
* Handles both the string shape (OpenAI/plain) and the array-of-blocks
|
|
76
|
+
* shape (Anthropic/Bedrock).
|
|
77
|
+
*/
|
|
78
|
+
function extractAIText(msg) {
|
|
79
|
+
const content = msg.content;
|
|
80
|
+
if (typeof content === 'string')
|
|
81
|
+
return content;
|
|
82
|
+
if (!Array.isArray(content))
|
|
83
|
+
return '';
|
|
84
|
+
return content
|
|
85
|
+
.filter((b) => b.type === 'text' && typeof b.text === 'string')
|
|
86
|
+
.map((b) => b.text ?? '')
|
|
87
|
+
.join('\n');
|
|
88
|
+
}
|
|
89
|
+
/* -------------------------------------------------------------------------- */
|
|
90
|
+
/* Strategy 1: cleaned parent history (handoff target / root subgraph) */
|
|
91
|
+
/* -------------------------------------------------------------------------- */
|
|
92
|
+
/**
|
|
93
|
+
* Prepare messages for a handoff child agent.
|
|
94
|
+
*
|
|
95
|
+
* Handles two problems that break Bedrock/Anthropic conversations:
|
|
96
|
+
*
|
|
97
|
+
* 1. **Orphaned tool_use**: The parent's AI message contains a `tool_use`
|
|
98
|
+
* block for the handoff tool itself, with no matching `tool_result`.
|
|
99
|
+
* Providers (Bedrock/Anthropic) reject this.
|
|
100
|
+
*
|
|
101
|
+
* 2. **Paired tool_use/tool_result in history**: The child may not have
|
|
102
|
+
* the same tools as the parent. Bedrock requires `toolConfig` when any
|
|
103
|
+
* tool_use/tool_result blocks exist in the history. Compacting these
|
|
104
|
+
* into text summaries avoids the requirement and reduces context bloat.
|
|
105
|
+
*
|
|
106
|
+
* Also ensures the tail is a HumanMessage — some providers reject a
|
|
107
|
+
* conversation that ends with an assistant message.
|
|
108
|
+
*
|
|
109
|
+
* @param messages - Current state messages from the parent
|
|
110
|
+
* @returns A sanitized copy, safe to pass to any provider as the child's
|
|
111
|
+
* input regardless of which tools the child has registered.
|
|
112
|
+
*/
|
|
113
|
+
function prepareHandoffMessages(messages$1) {
|
|
114
|
+
if (messages$1.length === 0)
|
|
115
|
+
return messages$1;
|
|
116
|
+
/** Collect tool_result IDs so we know which tool_use blocks are paired */
|
|
117
|
+
const pairedToolCallIds = new Set();
|
|
118
|
+
for (const msg of messages$1) {
|
|
119
|
+
if (msg.getType() === 'tool') {
|
|
120
|
+
const tm = msg;
|
|
121
|
+
if (tm.tool_call_id)
|
|
122
|
+
pairedToolCallIds.add(tm.tool_call_id);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Pass 1: Drop all ToolMessages (paired ones are compacted in pass 2),
|
|
127
|
+
* rewrite AI messages with tool_calls into plain-text summaries, leave
|
|
128
|
+
* other messages untouched.
|
|
129
|
+
*/
|
|
130
|
+
const cleaned = [];
|
|
131
|
+
for (const msg of messages$1) {
|
|
132
|
+
if (msg.getType() === 'tool')
|
|
133
|
+
continue;
|
|
134
|
+
if (msg.getType() !== 'ai') {
|
|
135
|
+
cleaned.push(msg);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const aiMsg = msg;
|
|
139
|
+
const toolCalls = aiMsg.tool_calls ?? [];
|
|
140
|
+
if (toolCalls.length === 0) {
|
|
141
|
+
cleaned.push(msg);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const textContent = extractAIText(aiMsg);
|
|
145
|
+
const toolSummaries = [];
|
|
146
|
+
for (const tc of toolCalls) {
|
|
147
|
+
if (tc.id != null && pairedToolCallIds.has(tc.id)) {
|
|
148
|
+
const toolResult = messages$1.find((m) => m.getType() === 'tool' && m.tool_call_id === tc.id);
|
|
149
|
+
const resultContent = toolResult
|
|
150
|
+
? typeof toolResult.content === 'string'
|
|
151
|
+
? toolResult.content.slice(0, 500)
|
|
152
|
+
: '[complex result]'
|
|
153
|
+
: '[no result]';
|
|
154
|
+
toolSummaries.push(`[Tool "${tc.name}": ${resultContent}]`);
|
|
155
|
+
}
|
|
156
|
+
// Orphaned tool_use blocks (no matching result) are silently dropped.
|
|
157
|
+
}
|
|
158
|
+
const parts = [textContent, ...toolSummaries].filter(Boolean);
|
|
159
|
+
if (parts.length > 0) {
|
|
160
|
+
cleaned.push(new messages.AIMessage({ content: parts.join('\n\n'), id: aiMsg.id }));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Ensure messages end with a HumanMessage. After stripping tool artifacts
|
|
165
|
+
* the tail may be an AIMessage, which Bedrock/VertexAI reject. Convert it
|
|
166
|
+
* to a HumanMessage preserving whatever text content was present, or drop
|
|
167
|
+
* it entirely if empty.
|
|
168
|
+
*/
|
|
169
|
+
if (cleaned.length > 0 && cleaned[cleaned.length - 1].getType() === 'ai') {
|
|
170
|
+
const lastAI = cleaned[cleaned.length - 1];
|
|
171
|
+
const content = typeof lastAI.content === 'string' ? lastAI.content : '';
|
|
172
|
+
if (content.trim()) {
|
|
173
|
+
cleaned[cleaned.length - 1] = new messages.HumanMessage(`${HANDOFF_TAIL_CONTEXT_PREFIX}${content}`);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
cleaned.pop();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return cleaned;
|
|
180
|
+
}
|
|
181
|
+
/* -------------------------------------------------------------------------- */
|
|
182
|
+
/* Strategy 2: isolated fresh session (downstream scoped-subgraph child) */
|
|
183
|
+
/* -------------------------------------------------------------------------- */
|
|
184
|
+
/**
|
|
185
|
+
* Build an ISOLATED message context for a downstream scoped-subgraph node.
|
|
186
|
+
*
|
|
187
|
+
* Unlike `prepareHandoffMessages` (which cleans up tool_use artifacts but
|
|
188
|
+
* preserves most of the parent history), this helper produces a fresh
|
|
189
|
+
* minimal context containing only:
|
|
190
|
+
*
|
|
191
|
+
* 1. The original user request (first HumanMessage in the history)
|
|
192
|
+
* 2. A synthetic HumanMessage summarizing the upstream agent's final
|
|
193
|
+
* text output and directing the downstream agent to act on it
|
|
194
|
+
*
|
|
195
|
+
* Tool_use / tool_result blocks from the upstream agent are discarded —
|
|
196
|
+
* the downstream agent shouldn't reason about how the upstream agent did
|
|
197
|
+
* its work, only about the result.
|
|
198
|
+
*
|
|
199
|
+
* This "fresh subagent session" pattern is the primary defense against
|
|
200
|
+
* schema confusion / malformed tool_use JSON that occurs when downstream
|
|
201
|
+
* models see a noisy upstream conversation.
|
|
202
|
+
*
|
|
203
|
+
* Defensive fallback: if the messages array contains neither a user
|
|
204
|
+
* message nor a non-empty upstream AI message, return the input unchanged
|
|
205
|
+
* so the caller still has something to invoke on. This only matters for
|
|
206
|
+
* malformed state fixtures in tests.
|
|
207
|
+
*/
|
|
208
|
+
function prepareIsolatedChildMessages(messages$1) {
|
|
209
|
+
if (messages$1.length === 0)
|
|
210
|
+
return messages$1;
|
|
211
|
+
/** First HumanMessage is the original user request */
|
|
212
|
+
const originalUser = messages$1.find((m) => m.getType() === 'human');
|
|
213
|
+
/** Most recent AIMessage with non-empty text content */
|
|
214
|
+
let upstreamText = '';
|
|
215
|
+
for (let i = messages$1.length - 1; i >= 0; i--) {
|
|
216
|
+
const msg = messages$1[i];
|
|
217
|
+
if (msg.getType() !== 'ai')
|
|
218
|
+
continue;
|
|
219
|
+
const text = extractAIText(msg);
|
|
220
|
+
if (text.trim()) {
|
|
221
|
+
upstreamText = text;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const result = [];
|
|
226
|
+
if (originalUser)
|
|
227
|
+
result.push(originalUser);
|
|
228
|
+
if (upstreamText.trim()) {
|
|
229
|
+
result.push(new messages.HumanMessage(buildIsolatedChildPrompt(upstreamText)));
|
|
230
|
+
}
|
|
231
|
+
else if (result.length === 0) {
|
|
232
|
+
/** Defensive: nothing to isolate — fall back to raw messages */
|
|
233
|
+
return messages$1;
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
exports.HANDOFF_TAIL_CONTEXT_PREFIX = HANDOFF_TAIL_CONTEXT_PREFIX;
|
|
239
|
+
exports.buildIsolatedChildPrompt = buildIsolatedChildPrompt;
|
|
240
|
+
exports.prepareHandoffMessages = prepareHandoffMessages;
|
|
241
|
+
exports.prepareIsolatedChildMessages = prepareIsolatedChildMessages;
|
|
242
|
+
//# sourceMappingURL=childAgentContext.cjs.map
|