@illuma-ai/agents 1.1.25 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs +20 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/spawnPath.cjs +104 -0
- package/dist/cjs/common/spawnPath.cjs.map +1 -0
- package/dist/cjs/graphs/Graph.cjs +87 -31
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/HandoffRegistry.cjs +143 -0
- package/dist/cjs/graphs/HandoffRegistry.cjs.map +1 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs +587 -184
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/graphs/phases/flushLoop.cjs +214 -0
- package/dist/cjs/graphs/phases/flushLoop.cjs.map +1 -0
- package/dist/cjs/graphs/phases/memoryFlushPhase.cjs +102 -0
- package/dist/cjs/graphs/phases/memoryFlushPhase.cjs.map +1 -0
- package/dist/cjs/llm/bedrock/index.cjs +4 -3
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +115 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/memory/citations.cjs +69 -0
- package/dist/cjs/memory/citations.cjs.map +1 -0
- package/dist/cjs/memory/compositeBackend.cjs +60 -0
- package/dist/cjs/memory/compositeBackend.cjs.map +1 -0
- package/dist/cjs/memory/constants.cjs +232 -0
- package/dist/cjs/memory/constants.cjs.map +1 -0
- package/dist/cjs/memory/embeddings.cjs +151 -0
- package/dist/cjs/memory/embeddings.cjs.map +1 -0
- package/dist/cjs/memory/factory.cjs +95 -0
- package/dist/cjs/memory/factory.cjs.map +1 -0
- package/dist/cjs/memory/migrate.cjs +81 -0
- package/dist/cjs/memory/migrate.cjs.map +1 -0
- package/dist/cjs/memory/mmr.cjs +138 -0
- package/dist/cjs/memory/mmr.cjs.map +1 -0
- package/dist/cjs/memory/paths.cjs +217 -0
- package/dist/cjs/memory/paths.cjs.map +1 -0
- package/dist/cjs/memory/pgvectorStore.cjs +225 -0
- package/dist/cjs/memory/pgvectorStore.cjs.map +1 -0
- package/dist/cjs/memory/recallTracking.cjs +98 -0
- package/dist/cjs/memory/recallTracking.cjs.map +1 -0
- package/dist/cjs/memory/schema.sql +51 -0
- package/dist/cjs/memory/temporalDecay.cjs +118 -0
- package/dist/cjs/memory/temporalDecay.cjs.map +1 -0
- package/dist/cjs/nodes/ApprovalGateNode.cjs +1 -1
- package/dist/cjs/nodes/ApprovalGateNode.cjs.map +1 -1
- package/dist/cjs/prompts/memoryFlushPrompt.cjs +49 -0
- package/dist/cjs/prompts/memoryFlushPrompt.cjs.map +1 -0
- package/dist/cjs/run.cjs +16 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +4 -4
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/AskUser.cjs +6 -1
- package/dist/cjs/tools/AskUser.cjs.map +1 -1
- package/dist/cjs/tools/BrowserTools.cjs +1 -1
- package/dist/cjs/tools/BrowserTools.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +127 -10
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/approval/constants.cjs +2 -2
- package/dist/cjs/tools/approval/constants.cjs.map +1 -1
- package/dist/cjs/tools/memory/index.cjs +58 -0
- package/dist/cjs/tools/memory/index.cjs.map +1 -0
- package/dist/cjs/tools/memory/memoryAppendTool.cjs +69 -0
- package/dist/cjs/tools/memory/memoryAppendTool.cjs.map +1 -0
- package/dist/cjs/tools/memory/memoryGetTool.cjs +49 -0
- package/dist/cjs/tools/memory/memoryGetTool.cjs.map +1 -0
- package/dist/cjs/tools/memory/memorySearchTool.cjs +65 -0
- package/dist/cjs/tools/memory/memorySearchTool.cjs.map +1 -0
- package/dist/cjs/tools/memory/shared.cjs +106 -0
- package/dist/cjs/tools/memory/shared.cjs.map +1 -0
- package/dist/cjs/types/graph.cjs.map +1 -1
- package/dist/cjs/utils/childAgentContext.cjs +242 -0
- package/dist/cjs/utils/childAgentContext.cjs.map +1 -0
- package/dist/cjs/utils/events.cjs +36 -4
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/cjs/utils/finishReasons.cjs +44 -0
- package/dist/cjs/utils/finishReasons.cjs.map +1 -0
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/logging.cjs +34 -0
- package/dist/cjs/utils/logging.cjs.map +1 -0
- package/dist/cjs/utils/toolCallNormalization.cjs +250 -0
- package/dist/cjs/utils/toolCallNormalization.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +20 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/spawnPath.mjs +95 -0
- package/dist/esm/common/spawnPath.mjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +87 -31
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/HandoffRegistry.mjs +141 -0
- package/dist/esm/graphs/HandoffRegistry.mjs.map +1 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs +587 -184
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/graphs/phases/flushLoop.mjs +209 -0
- package/dist/esm/graphs/phases/flushLoop.mjs.map +1 -0
- package/dist/esm/graphs/phases/memoryFlushPhase.mjs +99 -0
- package/dist/esm/graphs/phases/memoryFlushPhase.mjs.map +1 -0
- package/dist/esm/llm/bedrock/index.mjs +4 -3
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/main.mjs +21 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/memory/citations.mjs +64 -0
- package/dist/esm/memory/citations.mjs.map +1 -0
- package/dist/esm/memory/compositeBackend.mjs +58 -0
- package/dist/esm/memory/compositeBackend.mjs.map +1 -0
- package/dist/esm/memory/constants.mjs +198 -0
- package/dist/esm/memory/constants.mjs.map +1 -0
- package/dist/esm/memory/embeddings.mjs +148 -0
- package/dist/esm/memory/embeddings.mjs.map +1 -0
- package/dist/esm/memory/factory.mjs +93 -0
- package/dist/esm/memory/factory.mjs.map +1 -0
- package/dist/esm/memory/migrate.mjs +78 -0
- package/dist/esm/memory/migrate.mjs.map +1 -0
- package/dist/esm/memory/mmr.mjs +130 -0
- package/dist/esm/memory/mmr.mjs.map +1 -0
- package/dist/esm/memory/paths.mjs +207 -0
- package/dist/esm/memory/paths.mjs.map +1 -0
- package/dist/esm/memory/pgvectorStore.mjs +223 -0
- package/dist/esm/memory/pgvectorStore.mjs.map +1 -0
- package/dist/esm/memory/recallTracking.mjs +94 -0
- package/dist/esm/memory/recallTracking.mjs.map +1 -0
- package/dist/esm/memory/schema.sql +51 -0
- package/dist/esm/memory/temporalDecay.mjs +110 -0
- package/dist/esm/memory/temporalDecay.mjs.map +1 -0
- package/dist/esm/nodes/ApprovalGateNode.mjs +1 -1
- package/dist/esm/nodes/ApprovalGateNode.mjs.map +1 -1
- package/dist/esm/prompts/memoryFlushPrompt.mjs +44 -0
- package/dist/esm/prompts/memoryFlushPrompt.mjs.map +1 -0
- package/dist/esm/run.mjs +16 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +4 -4
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/AskUser.mjs +6 -1
- package/dist/esm/tools/AskUser.mjs.map +1 -1
- package/dist/esm/tools/BrowserTools.mjs +1 -1
- package/dist/esm/tools/BrowserTools.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +128 -11
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/approval/constants.mjs +2 -2
- package/dist/esm/tools/approval/constants.mjs.map +1 -1
- package/dist/esm/tools/memory/index.mjs +46 -0
- package/dist/esm/tools/memory/index.mjs.map +1 -0
- package/dist/esm/tools/memory/memoryAppendTool.mjs +67 -0
- package/dist/esm/tools/memory/memoryAppendTool.mjs.map +1 -0
- package/dist/esm/tools/memory/memoryGetTool.mjs +47 -0
- package/dist/esm/tools/memory/memoryGetTool.mjs.map +1 -0
- package/dist/esm/tools/memory/memorySearchTool.mjs +63 -0
- package/dist/esm/tools/memory/memorySearchTool.mjs.map +1 -0
- package/dist/esm/tools/memory/shared.mjs +98 -0
- package/dist/esm/tools/memory/shared.mjs.map +1 -0
- package/dist/esm/types/graph.mjs.map +1 -1
- package/dist/esm/utils/childAgentContext.mjs +237 -0
- package/dist/esm/utils/childAgentContext.mjs.map +1 -0
- package/dist/esm/utils/events.mjs +36 -5
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/esm/utils/finishReasons.mjs +41 -0
- package/dist/esm/utils/finishReasons.mjs.map +1 -0
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/logging.mjs +31 -0
- package/dist/esm/utils/logging.mjs.map +1 -0
- package/dist/esm/utils/toolCallNormalization.mjs +247 -0
- package/dist/esm/utils/toolCallNormalization.mjs.map +1 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/common/spawnPath.d.ts +59 -0
- package/dist/types/graphs/HandoffRegistry.d.ts +97 -0
- package/dist/types/graphs/MultiAgentGraph.d.ts +58 -18
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/graphs/phases/flushLoop.d.ts +106 -0
- package/dist/types/graphs/phases/memoryFlushPhase.d.ts +100 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/memory/__tests__/mockBackend.d.ts +40 -0
- package/dist/types/memory/citations.d.ts +39 -0
- package/dist/types/memory/compositeBackend.d.ts +30 -0
- package/dist/types/memory/constants.d.ts +121 -0
- package/dist/types/memory/embeddings.d.ts +15 -0
- package/dist/types/memory/factory.d.ts +23 -0
- package/dist/types/memory/index.d.ts +21 -0
- package/dist/types/memory/migrate.d.ts +14 -0
- package/dist/types/memory/mmr.d.ts +50 -0
- package/dist/types/memory/paths.d.ts +107 -0
- package/dist/types/memory/pgvectorStore.d.ts +56 -0
- package/dist/types/memory/recallTracking.d.ts +30 -0
- package/dist/types/memory/temporalDecay.d.ts +53 -0
- package/dist/types/memory/types.d.ts +182 -0
- package/dist/types/prompts/memoryFlushPrompt.d.ts +54 -0
- package/dist/types/run.d.ts +1 -0
- package/dist/types/tools/AskUser.d.ts +1 -1
- package/dist/types/tools/BrowserTools.d.ts +2 -2
- package/dist/types/tools/approval/constants.d.ts +2 -2
- package/dist/types/tools/memory/index.d.ts +39 -0
- package/dist/types/tools/memory/memoryAppendTool.d.ts +27 -0
- package/dist/types/tools/memory/memoryGetTool.d.ts +22 -0
- package/dist/types/tools/memory/memorySearchTool.d.ts +22 -0
- package/dist/types/tools/memory/shared.d.ts +106 -0
- package/dist/types/types/graph.d.ts +16 -3
- package/dist/types/utils/childAgentContext.d.ts +99 -0
- package/dist/types/utils/events.d.ts +21 -0
- package/dist/types/utils/finishReasons.d.ts +32 -0
- package/dist/types/utils/logging.d.ts +2 -0
- package/dist/types/utils/toolCallNormalization.d.ts +44 -0
- package/package.json +6 -4
- package/src/agents/AgentContext.ts +26 -3
- package/src/common/__tests__/enum.test.ts +4 -2
- package/src/common/__tests__/spawnPath.test.ts +110 -0
- package/src/common/index.ts +1 -0
- package/src/common/spawnPath.ts +101 -0
- package/src/graphs/Graph.ts +94 -43
- package/src/graphs/HandoffRegistry.ts +199 -0
- package/src/graphs/MultiAgentGraph.ts +694 -226
- package/src/graphs/__tests__/HandoffRegistry.test.ts +410 -0
- package/src/graphs/__tests__/multi-agent-delegate.test.ts +61 -16
- package/src/graphs/__tests__/multi-agent-edges.test.ts +4 -2
- package/src/graphs/__tests__/multi-agent-nested-subgraph.test.ts +221 -0
- package/src/graphs/__tests__/structured-output.integration.test.ts +212 -118
- package/src/graphs/contextManagement.e2e.test.ts +1 -1
- package/src/graphs/index.ts +1 -0
- package/src/graphs/phases/__tests__/flushLoop.test.ts +264 -0
- package/src/graphs/phases/__tests__/memoryFlushPhase.test.ts +37 -0
- package/src/graphs/phases/__tests__/runMemoryFlush.test.ts +150 -0
- package/src/graphs/phases/flushLoop.ts +303 -0
- package/src/graphs/phases/memoryFlushPhase.ts +209 -0
- package/src/index.ts +30 -1
- package/src/llm/bedrock/index.ts +4 -5
- package/src/memory/__tests__/citations.test.ts +61 -0
- package/src/memory/__tests__/compositeBackend.test.ts +79 -0
- package/src/memory/__tests__/isolation.test.ts +206 -0
- package/src/memory/__tests__/mmr.test.ts +148 -0
- package/src/memory/__tests__/mockBackend.ts +161 -0
- package/src/memory/__tests__/paths.test.ts +168 -0
- package/src/memory/__tests__/recallTracking.test.ts +96 -0
- package/src/memory/__tests__/temporalDecay.test.ts +151 -0
- package/src/memory/citations.ts +80 -0
- package/src/memory/compositeBackend.ts +99 -0
- package/src/memory/constants.ts +229 -0
- package/src/memory/embeddings.ts +188 -0
- package/src/memory/factory.ts +111 -0
- package/src/memory/index.ts +46 -0
- package/src/memory/migrate.ts +116 -0
- package/src/memory/mmr.ts +161 -0
- package/src/memory/paths.ts +258 -0
- package/src/memory/pgvectorStore.ts +324 -0
- package/src/memory/recallTracking.ts +127 -0
- package/src/memory/schema.sql +51 -0
- package/src/memory/temporalDecay.ts +134 -0
- package/src/memory/types.ts +185 -0
- package/src/nodes/ApprovalGateNode.ts +4 -10
- package/src/nodes/__tests__/ApprovalGateNode.test.ts +11 -20
- package/src/prompts/memoryFlushPrompt.ts +78 -0
- package/src/run.ts +17 -6
- package/src/scripts/test-bedrock-handoff-autonomous.ts +56 -20
- package/src/specs/agent-handoffs-bedrock.integration.test.ts +8 -5
- package/src/specs/agent-handoffs.test.ts +8 -2
- package/src/stream.ts +4 -6
- package/src/tools/AskUser.ts +7 -2
- package/src/tools/BrowserTools.ts +3 -5
- package/src/tools/ToolNode.ts +150 -13
- package/src/tools/__tests__/ToolApproval.test.ts +22 -9
- package/src/tools/approval/__tests__/constants.test.ts +4 -4
- package/src/tools/approval/constants.ts +2 -2
- package/src/tools/memory/__tests__/memoryTools.test.ts +205 -0
- package/src/tools/memory/index.ts +96 -0
- package/src/tools/memory/memoryAppendTool.ts +101 -0
- package/src/tools/memory/memoryGetTool.ts +53 -0
- package/src/tools/memory/memorySearchTool.ts +80 -0
- package/src/tools/memory/shared.ts +169 -0
- package/src/tools/search/search.test.ts +6 -1
- package/src/types/graph.ts +16 -3
- package/src/utils/__tests__/childAgentContext.test.ts +217 -0
- package/src/utils/__tests__/finishReasons.test.ts +55 -0
- package/src/utils/__tests__/toolCallNormalization.test.ts +181 -0
- package/src/utils/childAgentContext.ts +259 -0
- package/src/utils/events.ts +37 -4
- package/src/utils/finishReasons.ts +40 -0
- package/src/utils/llm.ts +0 -1
- package/src/utils/logging.ts +45 -8
- package/src/utils/toolCallNormalization.ts +271 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the nested sequence-in-handoff scoped subgraph logic.
|
|
3
|
+
*
|
|
4
|
+
* When an agent is a handoff target AND has its own downstream
|
|
5
|
+
* sequence/transfer edges (e.g. researcher → prod_assistant), the parent's
|
|
6
|
+
* `subgraph.invoke()` must run the full local workflow before returning.
|
|
7
|
+
*
|
|
8
|
+
* The implementation lives in three private methods on MultiAgentGraph:
|
|
9
|
+
* - computeReachableViaNonHandoff(rootAgentId): BFS over sequence+transfer
|
|
10
|
+
* edges (handoff edges excluded), returns the local scope set
|
|
11
|
+
* - createAgentSubgraph(agentId): fast-path single-node vs scoped subgraph
|
|
12
|
+
* - buildScopedSubgraph(rootAgentId, agentIds): mini StateGraph wiring
|
|
13
|
+
*
|
|
14
|
+
* These tests mirror the pattern in `multi-agent-edges.test.ts`: extract the
|
|
15
|
+
* pure algorithm as a local function matching the private method 1:1 and
|
|
16
|
+
* exercise the edge cases. This keeps the test unit-level (no LLM mocks, no
|
|
17
|
+
* real agent instantiation) while still guarding the architectural fix.
|
|
18
|
+
*
|
|
19
|
+
* See docs/multi-agent-nesting-architecture.md §6.
|
|
20
|
+
*/
|
|
21
|
+
import { EdgeType } from '@/common';
|
|
22
|
+
import type { GraphEdge } from '@/types';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* BFS across sequence + transfer edges (NOT handoff edges).
|
|
26
|
+
* Mirrors MultiAgentGraph.computeReachableViaNonHandoff().
|
|
27
|
+
*/
|
|
28
|
+
function computeReachableViaNonHandoff(
|
|
29
|
+
rootAgentId: string,
|
|
30
|
+
sequenceEdges: GraphEdge[],
|
|
31
|
+
transferEdges: GraphEdge[],
|
|
32
|
+
knownAgents: Set<string>
|
|
33
|
+
): Set<string> {
|
|
34
|
+
const reachable = new Set<string>([rootAgentId]);
|
|
35
|
+
const queue: string[] = [rootAgentId];
|
|
36
|
+
const localEdges = [...sequenceEdges, ...transferEdges];
|
|
37
|
+
while (queue.length > 0) {
|
|
38
|
+
const current = queue.shift()!;
|
|
39
|
+
for (const edge of localEdges) {
|
|
40
|
+
const sources = Array.isArray(edge.from) ? edge.from : [edge.from];
|
|
41
|
+
if (!sources.includes(current)) continue;
|
|
42
|
+
const dests = Array.isArray(edge.to) ? edge.to : [edge.to];
|
|
43
|
+
for (const dest of dests) {
|
|
44
|
+
if (!reachable.has(dest) && knownAgents.has(dest)) {
|
|
45
|
+
reachable.add(dest);
|
|
46
|
+
queue.push(dest);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return reachable;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Mirrors the fast-path decision in MultiAgentGraph.createAgentSubgraph():
|
|
56
|
+
* if only the root itself is reachable, return "single-node"; otherwise
|
|
57
|
+
* "scoped-subgraph".
|
|
58
|
+
*/
|
|
59
|
+
function decideSubgraphShape(
|
|
60
|
+
reachable: Set<string>
|
|
61
|
+
): 'single-node' | 'scoped-subgraph' {
|
|
62
|
+
return reachable.size === 1 ? 'single-node' : 'scoped-subgraph';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// computeReachableViaNonHandoff
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
describe('computeReachableViaNonHandoff', () => {
|
|
69
|
+
it('returns just the root when there are no outgoing edges', () => {
|
|
70
|
+
const known = new Set(['researcher']);
|
|
71
|
+
const reachable = computeReachableViaNonHandoff(
|
|
72
|
+
'researcher',
|
|
73
|
+
[],
|
|
74
|
+
[],
|
|
75
|
+
known
|
|
76
|
+
);
|
|
77
|
+
expect(Array.from(reachable)).toEqual(['researcher']);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('walks a single downstream sequence edge (researcher → prod_assistant)', () => {
|
|
81
|
+
const known = new Set(['researcher', 'prod_assistant']);
|
|
82
|
+
const sequenceEdges: GraphEdge[] = [
|
|
83
|
+
{ from: 'researcher', to: 'prod_assistant', edgeType: EdgeType.SEQUENCE },
|
|
84
|
+
];
|
|
85
|
+
const reachable = computeReachableViaNonHandoff(
|
|
86
|
+
'researcher',
|
|
87
|
+
sequenceEdges,
|
|
88
|
+
[],
|
|
89
|
+
known
|
|
90
|
+
);
|
|
91
|
+
expect(reachable.size).toBe(2);
|
|
92
|
+
expect(reachable.has('researcher')).toBe(true);
|
|
93
|
+
expect(reachable.has('prod_assistant')).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('walks transitive sequence chain (a → b → c)', () => {
|
|
97
|
+
const known = new Set(['a', 'b', 'c']);
|
|
98
|
+
const seq: GraphEdge[] = [
|
|
99
|
+
{ from: 'a', to: 'b', edgeType: EdgeType.SEQUENCE },
|
|
100
|
+
{ from: 'b', to: 'c', edgeType: EdgeType.SEQUENCE },
|
|
101
|
+
];
|
|
102
|
+
const reachable = computeReachableViaNonHandoff('a', seq, [], known);
|
|
103
|
+
expect(reachable.size).toBe(3);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('skips handoff edges — downstream handoff targets are out of scope', () => {
|
|
107
|
+
const known = new Set(['researcher', 'prod_assistant', 'critic']);
|
|
108
|
+
const sequenceEdges: GraphEdge[] = [
|
|
109
|
+
{ from: 'researcher', to: 'prod_assistant', edgeType: EdgeType.SEQUENCE },
|
|
110
|
+
];
|
|
111
|
+
// critic is NOT reachable via non-handoff walk even though a handoff edge
|
|
112
|
+
// would connect prod_assistant → critic. Handoff edges are excluded by
|
|
113
|
+
// construction: the caller only passes sequence + transfer edges.
|
|
114
|
+
const reachable = computeReachableViaNonHandoff(
|
|
115
|
+
'researcher',
|
|
116
|
+
sequenceEdges,
|
|
117
|
+
[],
|
|
118
|
+
known
|
|
119
|
+
);
|
|
120
|
+
expect(reachable.has('critic')).toBe(false);
|
|
121
|
+
expect(reachable.size).toBe(2);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('follows transfer edges (Command-based routing)', () => {
|
|
125
|
+
const known = new Set(['a', 'b']);
|
|
126
|
+
const transferEdges: GraphEdge[] = [
|
|
127
|
+
{ from: 'a', to: 'b', edgeType: EdgeType.TRANSFER },
|
|
128
|
+
];
|
|
129
|
+
const reachable = computeReachableViaNonHandoff(
|
|
130
|
+
'a',
|
|
131
|
+
[],
|
|
132
|
+
transferEdges,
|
|
133
|
+
known
|
|
134
|
+
);
|
|
135
|
+
expect(reachable.size).toBe(2);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('is robust to cycles (a → b → a)', () => {
|
|
139
|
+
const known = new Set(['a', 'b']);
|
|
140
|
+
const seq: GraphEdge[] = [
|
|
141
|
+
{ from: 'a', to: 'b', edgeType: EdgeType.SEQUENCE },
|
|
142
|
+
{ from: 'b', to: 'a', edgeType: EdgeType.SEQUENCE },
|
|
143
|
+
];
|
|
144
|
+
const reachable = computeReachableViaNonHandoff('a', seq, [], known);
|
|
145
|
+
expect(reachable.size).toBe(2);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('ignores destinations that are not known agents (orphaned references)', () => {
|
|
149
|
+
const known = new Set(['researcher']);
|
|
150
|
+
const seq: GraphEdge[] = [
|
|
151
|
+
{ from: 'researcher', to: 'ghost_agent', edgeType: EdgeType.SEQUENCE },
|
|
152
|
+
];
|
|
153
|
+
const reachable = computeReachableViaNonHandoff(
|
|
154
|
+
'researcher',
|
|
155
|
+
seq,
|
|
156
|
+
[],
|
|
157
|
+
known
|
|
158
|
+
);
|
|
159
|
+
expect(Array.from(reachable)).toEqual(['researcher']);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('expands fan-out sequence (single source → multiple destinations)', () => {
|
|
163
|
+
const known = new Set(['root', 'a', 'b']);
|
|
164
|
+
const seq: GraphEdge[] = [
|
|
165
|
+
{ from: 'root', to: ['a', 'b'], edgeType: EdgeType.SEQUENCE },
|
|
166
|
+
];
|
|
167
|
+
const reachable = computeReachableViaNonHandoff('root', seq, [], known);
|
|
168
|
+
expect(reachable.size).toBe(3);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// createAgentSubgraph fast-path decision
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
describe('createAgentSubgraph shape decision', () => {
|
|
176
|
+
it('returns single-node when the handoff target has no local workflow', () => {
|
|
177
|
+
const known = new Set(['researcher']);
|
|
178
|
+
const reachable = computeReachableViaNonHandoff(
|
|
179
|
+
'researcher',
|
|
180
|
+
[],
|
|
181
|
+
[],
|
|
182
|
+
known
|
|
183
|
+
);
|
|
184
|
+
expect(decideSubgraphShape(reachable)).toBe('single-node');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('returns scoped-subgraph when the handoff target has a downstream sequence', () => {
|
|
188
|
+
const known = new Set(['researcher', 'prod_assistant']);
|
|
189
|
+
const seq: GraphEdge[] = [
|
|
190
|
+
{ from: 'researcher', to: 'prod_assistant', edgeType: EdgeType.SEQUENCE },
|
|
191
|
+
];
|
|
192
|
+
const reachable = computeReachableViaNonHandoff(
|
|
193
|
+
'researcher',
|
|
194
|
+
seq,
|
|
195
|
+
[],
|
|
196
|
+
known
|
|
197
|
+
);
|
|
198
|
+
expect(decideSubgraphShape(reachable)).toBe('scoped-subgraph');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('returns scoped-subgraph for the orchestrator → handoff → researcher → sequence case', () => {
|
|
202
|
+
// Full topology:
|
|
203
|
+
// orchestrator --handoff--> researcher --sequence--> prod_assistant
|
|
204
|
+
// The handoff edge is NOT passed here (only seq + transfer), so the
|
|
205
|
+
// researcher scope correctly contains [researcher, prod_assistant].
|
|
206
|
+
const known = new Set(['orchestrator', 'researcher', 'prod_assistant']);
|
|
207
|
+
const seq: GraphEdge[] = [
|
|
208
|
+
{ from: 'researcher', to: 'prod_assistant', edgeType: EdgeType.SEQUENCE },
|
|
209
|
+
];
|
|
210
|
+
const reachable = computeReachableViaNonHandoff(
|
|
211
|
+
'researcher',
|
|
212
|
+
seq,
|
|
213
|
+
[],
|
|
214
|
+
known
|
|
215
|
+
);
|
|
216
|
+
expect(decideSubgraphShape(reachable)).toBe('scoped-subgraph');
|
|
217
|
+
expect(reachable.has('orchestrator')).toBe(false);
|
|
218
|
+
expect(reachable.has('researcher')).toBe(true);
|
|
219
|
+
expect(reachable.has('prod_assistant')).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
});
|