@ddse/acm-adapters 0.5.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/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/langgraph.d.ts +81 -0
- package/dist/langgraph.d.ts.map +1 -0
- package/dist/langgraph.js +222 -0
- package/dist/langgraph.js.map +1 -0
- package/dist/msaf.d.ts +76 -0
- package/dist/msaf.d.ts.map +1 -0
- package/dist/msaf.js +269 -0
- package/dist/msaf.js.map +1 -0
- package/package.json +42 -0
- package/src/index.ts +3 -0
- package/src/langgraph.ts +312 -0
- package/src/msaf.ts +361 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
package/dist/msaf.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// Microsoft Agent Framework Adapter for ACM
|
|
2
|
+
import { InternalContextScopeImpl, } from '@ddse/acm-sdk';
|
|
3
|
+
import { createInstrumentedToolGetter } from '@ddse/acm-runtime';
|
|
4
|
+
/**
|
|
5
|
+
* Microsoft Agent Framework Adapter for ACM
|
|
6
|
+
*
|
|
7
|
+
* Converts ACM tasks into MS Agent Framework activities with proper
|
|
8
|
+
* hooks for policy, verification, and streaming.
|
|
9
|
+
*/
|
|
10
|
+
export class MSAgentFrameworkAdapter {
|
|
11
|
+
options;
|
|
12
|
+
activities = new Map();
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
// Warn if resume options are provided but not supported
|
|
16
|
+
if (options.resumeFrom || options.checkpointStore) {
|
|
17
|
+
console.warn('⚠️ MS Agent Framework adapter does not support resume functionality. ' +
|
|
18
|
+
'Use the runtime engine (--engine runtime) for resumable executions.');
|
|
19
|
+
}
|
|
20
|
+
this.buildActivities();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build activity handlers from ACM tasks
|
|
24
|
+
*/
|
|
25
|
+
buildActivities() {
|
|
26
|
+
const { plan, capabilityRegistry, toolRegistry, policy, stream, ledger } = this.options;
|
|
27
|
+
for (const taskSpec of plan.tasks) {
|
|
28
|
+
const handler = async (state) => {
|
|
29
|
+
try {
|
|
30
|
+
// Get task implementation
|
|
31
|
+
const capabilityName = taskSpec.capabilityRef || taskSpec.capability;
|
|
32
|
+
if (!capabilityName) {
|
|
33
|
+
throw new Error(`Task ${taskSpec.id} missing capability reference`);
|
|
34
|
+
}
|
|
35
|
+
const task = capabilityRegistry.resolve(capabilityName);
|
|
36
|
+
if (!task) {
|
|
37
|
+
throw new Error(`Capability ${capabilityName} not found`);
|
|
38
|
+
}
|
|
39
|
+
// Build run context
|
|
40
|
+
const allowedTools = new Set(this.options.nucleusConfig.allowedTools ?? []);
|
|
41
|
+
for (const tool of taskSpec.tools ?? []) {
|
|
42
|
+
allowedTools.add(tool.name);
|
|
43
|
+
}
|
|
44
|
+
const nucleus = this.options.nucleusFactory({
|
|
45
|
+
goalId: this.options.goal.id,
|
|
46
|
+
goalIntent: this.options.goal.intent,
|
|
47
|
+
planId: this.options.plan.id,
|
|
48
|
+
taskId: taskSpec.id,
|
|
49
|
+
contextRef: this.options.plan.contextRef,
|
|
50
|
+
context: state.context,
|
|
51
|
+
llmCall: this.options.nucleusConfig.llmCall,
|
|
52
|
+
hooks: this.options.nucleusConfig.hooks,
|
|
53
|
+
allowedTools: Array.from(allowedTools),
|
|
54
|
+
});
|
|
55
|
+
const internalScope = new InternalContextScopeImpl(entry => {
|
|
56
|
+
this.options.ledger?.append(entry.type, entry.details);
|
|
57
|
+
});
|
|
58
|
+
nucleus.setInternalContext(internalScope);
|
|
59
|
+
const getTool = createInstrumentedToolGetter({
|
|
60
|
+
taskId: taskSpec.id,
|
|
61
|
+
capability: capabilityName,
|
|
62
|
+
toolRegistry,
|
|
63
|
+
ledger,
|
|
64
|
+
});
|
|
65
|
+
const runContext = {
|
|
66
|
+
goal: this.options.goal,
|
|
67
|
+
context: state.context,
|
|
68
|
+
outputs: Object.fromEntries(state.outputs),
|
|
69
|
+
metrics: { costUsd: 0, elapsedSec: 0 },
|
|
70
|
+
getTool,
|
|
71
|
+
getCapabilityRegistry: () => capabilityRegistry,
|
|
72
|
+
stream,
|
|
73
|
+
nucleus,
|
|
74
|
+
internalContext: internalScope,
|
|
75
|
+
};
|
|
76
|
+
const preflight = await nucleus.preflight();
|
|
77
|
+
if (preflight.status === 'NEEDS_CONTEXT') {
|
|
78
|
+
throw new Error(`Task ${taskSpec.id} requires additional context retrieval: ${preflight.retrievalDirectives.join(', ')}`);
|
|
79
|
+
}
|
|
80
|
+
// Policy pre-check (PDP hook)
|
|
81
|
+
if (policy) {
|
|
82
|
+
const policyInput = task.policyInput?.(runContext, taskSpec.input || state.input) || {};
|
|
83
|
+
const decision = await policy.evaluate('task.pre', {
|
|
84
|
+
action: taskSpec.capability,
|
|
85
|
+
input: policyInput,
|
|
86
|
+
context: state.context,
|
|
87
|
+
});
|
|
88
|
+
if (!decision.allow) {
|
|
89
|
+
if (ledger) {
|
|
90
|
+
ledger.append('POLICY_PRE', {
|
|
91
|
+
taskId: taskSpec.id,
|
|
92
|
+
capability: taskSpec.capability,
|
|
93
|
+
allowed: false,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`Policy denied execution of ${taskSpec.capability}`);
|
|
97
|
+
}
|
|
98
|
+
if (ledger) {
|
|
99
|
+
ledger.append('POLICY_PRE', {
|
|
100
|
+
taskId: taskSpec.id,
|
|
101
|
+
capability: taskSpec.capability,
|
|
102
|
+
allowed: true,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Emit start event
|
|
107
|
+
stream?.emit('task', {
|
|
108
|
+
taskId: taskSpec.id,
|
|
109
|
+
status: 'started',
|
|
110
|
+
capability: taskSpec.capability,
|
|
111
|
+
});
|
|
112
|
+
// Execute task
|
|
113
|
+
const output = await task.execute(runContext, taskSpec.input || state.input);
|
|
114
|
+
// Verification (if provided)
|
|
115
|
+
const verificationExprs = task.verification?.() || [];
|
|
116
|
+
if (verificationExprs.length > 0) {
|
|
117
|
+
for (const expr of verificationExprs) {
|
|
118
|
+
try {
|
|
119
|
+
const func = new Function('output', `return ${expr}`);
|
|
120
|
+
const result = func(output);
|
|
121
|
+
if (!result) {
|
|
122
|
+
throw new Error(`Verification failed: ${expr}`);
|
|
123
|
+
}
|
|
124
|
+
if (ledger) {
|
|
125
|
+
ledger.append('VERIFICATION', {
|
|
126
|
+
taskId: taskSpec.id,
|
|
127
|
+
expression: expr,
|
|
128
|
+
passed: true,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (ledger) {
|
|
134
|
+
ledger.append('VERIFICATION', {
|
|
135
|
+
taskId: taskSpec.id,
|
|
136
|
+
expression: expr,
|
|
137
|
+
error: String(error),
|
|
138
|
+
passed: false,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Emit completion event
|
|
146
|
+
stream?.emit('task', {
|
|
147
|
+
taskId: taskSpec.id,
|
|
148
|
+
status: 'completed',
|
|
149
|
+
output,
|
|
150
|
+
});
|
|
151
|
+
// Log completion
|
|
152
|
+
if (ledger) {
|
|
153
|
+
ledger.append('TASK_END', {
|
|
154
|
+
taskId: taskSpec.id,
|
|
155
|
+
capability: taskSpec.capability,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const postcheck = await nucleus.postcheck(output);
|
|
159
|
+
if (postcheck.status === 'NEEDS_COMPENSATION' || postcheck.status === 'ESCALATE') {
|
|
160
|
+
throw new Error(`Task ${taskSpec.id} postcheck failed: ${postcheck.reason}`);
|
|
161
|
+
}
|
|
162
|
+
return output;
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
// Emit error event
|
|
166
|
+
stream?.emit('task', {
|
|
167
|
+
taskId: taskSpec.id,
|
|
168
|
+
status: 'failed',
|
|
169
|
+
error,
|
|
170
|
+
});
|
|
171
|
+
// Log error
|
|
172
|
+
if (ledger) {
|
|
173
|
+
ledger.append('ERROR', {
|
|
174
|
+
taskId: taskSpec.id,
|
|
175
|
+
error: String(error),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
this.activities.set(taskSpec.id, handler);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get activity handler for a task
|
|
186
|
+
*/
|
|
187
|
+
getActivity(taskId) {
|
|
188
|
+
return this.activities.get(taskId);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get all activities
|
|
192
|
+
*/
|
|
193
|
+
getAllActivities() {
|
|
194
|
+
return new Map(this.activities);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Execute workflow using MS Agent Framework pattern
|
|
198
|
+
*/
|
|
199
|
+
async execute() {
|
|
200
|
+
const { plan, context } = this.options;
|
|
201
|
+
const outputs = new Map();
|
|
202
|
+
// Build execution order based on edges
|
|
203
|
+
const executionOrder = this.topologicalSort(plan);
|
|
204
|
+
for (const taskId of executionOrder) {
|
|
205
|
+
const handler = this.activities.get(taskId);
|
|
206
|
+
if (!handler)
|
|
207
|
+
continue;
|
|
208
|
+
const taskSpec = plan.tasks.find((t) => t.id === taskId);
|
|
209
|
+
if (!taskSpec)
|
|
210
|
+
continue;
|
|
211
|
+
const state = {
|
|
212
|
+
taskId,
|
|
213
|
+
input: taskSpec.input || {},
|
|
214
|
+
context,
|
|
215
|
+
outputs,
|
|
216
|
+
};
|
|
217
|
+
const result = await handler(state);
|
|
218
|
+
outputs.set(taskId, result);
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
outputsByTask: Object.fromEntries(outputs),
|
|
222
|
+
ledger: this.options.ledger?.getEntries() || [],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Topological sort of tasks based on edges
|
|
227
|
+
*/
|
|
228
|
+
topologicalSort(plan) {
|
|
229
|
+
const inDegree = new Map();
|
|
230
|
+
const graph = new Map();
|
|
231
|
+
// Initialize
|
|
232
|
+
for (const task of plan.tasks) {
|
|
233
|
+
inDegree.set(task.id, 0);
|
|
234
|
+
graph.set(task.id, []);
|
|
235
|
+
}
|
|
236
|
+
// Build graph
|
|
237
|
+
for (const edge of plan.edges) {
|
|
238
|
+
graph.get(edge.from)?.push(edge.to);
|
|
239
|
+
inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);
|
|
240
|
+
}
|
|
241
|
+
// Find nodes with no incoming edges
|
|
242
|
+
const queue = [];
|
|
243
|
+
for (const [taskId, degree] of inDegree.entries()) {
|
|
244
|
+
if (degree === 0) {
|
|
245
|
+
queue.push(taskId);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const result = [];
|
|
249
|
+
while (queue.length > 0) {
|
|
250
|
+
const current = queue.shift();
|
|
251
|
+
result.push(current);
|
|
252
|
+
for (const neighbor of graph.get(current) || []) {
|
|
253
|
+
const newDegree = (inDegree.get(neighbor) || 0) - 1;
|
|
254
|
+
inDegree.set(neighbor, newDegree);
|
|
255
|
+
if (newDegree === 0) {
|
|
256
|
+
queue.push(neighbor);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Helper function to create MS Agent Framework adapter
|
|
265
|
+
*/
|
|
266
|
+
export function wrapAgentNodes(options) {
|
|
267
|
+
return new MSAgentFrameworkAdapter(options);
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=msaf.js.map
|
package/dist/msaf.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"msaf.js","sourceRoot":"","sources":["../src/msaf.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ddse/acm-adapters",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Framework adapters for ACM (LangGraph, Microsoft Agent Framework)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@ddse/acm-sdk": "0.5.0",
|
|
16
|
+
"@ddse/acm-runtime": "0.5.0"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@langchain/langgraph": "^0.2.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependenciesMeta": {
|
|
22
|
+
"@langchain/langgraph": {
|
|
23
|
+
"optional": true
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^20.0.0",
|
|
28
|
+
"typescript": "^5.3.0"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"acm",
|
|
32
|
+
"langgraph",
|
|
33
|
+
"microsoft-agent-framework",
|
|
34
|
+
"adapters"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"clean": "rm -rf dist",
|
|
40
|
+
"dev": "tsc --watch"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/index.ts
ADDED
package/src/langgraph.ts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// LangGraph Adapter for ACM
|
|
2
|
+
import {
|
|
3
|
+
InternalContextScopeImpl,
|
|
4
|
+
type Goal,
|
|
5
|
+
type Context,
|
|
6
|
+
type Plan,
|
|
7
|
+
type CapabilityRegistry,
|
|
8
|
+
type ToolRegistry,
|
|
9
|
+
type PolicyEngine,
|
|
10
|
+
type StreamSink,
|
|
11
|
+
type RunContext,
|
|
12
|
+
type NucleusFactory,
|
|
13
|
+
type NucleusConfig,
|
|
14
|
+
} from '@ddse/acm-sdk';
|
|
15
|
+
import { createInstrumentedToolGetter } from '@ddse/acm-runtime';
|
|
16
|
+
import type { MemoryLedger } from '@ddse/acm-runtime';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* LangGraph adapter options
|
|
20
|
+
*/
|
|
21
|
+
export interface LangGraphAdapterOptions {
|
|
22
|
+
goal: Goal;
|
|
23
|
+
context: Context;
|
|
24
|
+
plan: Plan;
|
|
25
|
+
capabilityRegistry: CapabilityRegistry;
|
|
26
|
+
toolRegistry: ToolRegistry;
|
|
27
|
+
policy?: PolicyEngine;
|
|
28
|
+
stream?: StreamSink;
|
|
29
|
+
ledger?: MemoryLedger;
|
|
30
|
+
resumeFrom?: string; // Checkpoint ID to resume from (optional, may not be supported)
|
|
31
|
+
checkpointStore?: any; // Checkpoint store (optional, may not be supported)
|
|
32
|
+
nucleusFactory: NucleusFactory;
|
|
33
|
+
nucleusConfig: {
|
|
34
|
+
llmCall: NucleusConfig['llmCall'];
|
|
35
|
+
hooks?: NucleusConfig['hooks'];
|
|
36
|
+
allowedTools?: string[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* LangGraph node state
|
|
42
|
+
*/
|
|
43
|
+
export interface GraphState {
|
|
44
|
+
taskId: string;
|
|
45
|
+
input: any;
|
|
46
|
+
output?: any;
|
|
47
|
+
error?: Error;
|
|
48
|
+
context: Context;
|
|
49
|
+
outputs: Map<string, any>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Convert ACM Plan to LangGraph-compatible structure
|
|
54
|
+
*
|
|
55
|
+
* This adapter converts ACM tasks and edges into LangGraph nodes and edges.
|
|
56
|
+
* Each ACM task becomes a LangGraph node, and guards become conditional edges.
|
|
57
|
+
*/
|
|
58
|
+
export class LangGraphAdapter {
|
|
59
|
+
constructor(private options: LangGraphAdapterOptions) {
|
|
60
|
+
// Warn if resume options are provided but not supported
|
|
61
|
+
if (options.resumeFrom || options.checkpointStore) {
|
|
62
|
+
console.warn(
|
|
63
|
+
'⚠️ LangGraph adapter does not support resume functionality. ' +
|
|
64
|
+
'Use the runtime engine (--engine runtime) for resumable executions.'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a LangGraph-compatible node function from an ACM task
|
|
71
|
+
*/
|
|
72
|
+
private createNodeFunction(taskId: string) {
|
|
73
|
+
return async (state: GraphState): Promise<Partial<GraphState>> => {
|
|
74
|
+
const { plan, capabilityRegistry, toolRegistry, policy, stream, ledger } = this.options;
|
|
75
|
+
|
|
76
|
+
// Find task spec in plan
|
|
77
|
+
const taskSpec = plan.tasks.find((t) => t.id === taskId);
|
|
78
|
+
if (!taskSpec) {
|
|
79
|
+
throw new Error(`Task ${taskId} not found in plan`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
// Get task implementation
|
|
84
|
+
const capabilityName = taskSpec.capabilityRef || taskSpec.capability;
|
|
85
|
+
if (!capabilityName) {
|
|
86
|
+
throw new Error(`Task ${taskId} missing capability reference`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const task = capabilityRegistry.resolve(capabilityName);
|
|
90
|
+
if (!task) {
|
|
91
|
+
throw new Error(`Capability ${capabilityName} not found`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Build run context
|
|
95
|
+
const allowedTools = new Set<string>(this.options.nucleusConfig.allowedTools ?? []);
|
|
96
|
+
for (const tool of taskSpec.tools ?? []) {
|
|
97
|
+
allowedTools.add(tool.name);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const nucleus = this.options.nucleusFactory({
|
|
101
|
+
goalId: this.options.goal.id,
|
|
102
|
+
goalIntent: this.options.goal.intent,
|
|
103
|
+
planId: plan.id,
|
|
104
|
+
taskId,
|
|
105
|
+
contextRef: plan.contextRef,
|
|
106
|
+
context: state.context,
|
|
107
|
+
llmCall: this.options.nucleusConfig.llmCall,
|
|
108
|
+
hooks: this.options.nucleusConfig.hooks,
|
|
109
|
+
allowedTools: Array.from(allowedTools),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const internalScope = new InternalContextScopeImpl(entry => {
|
|
113
|
+
this.options.ledger?.append(entry.type, entry.details);
|
|
114
|
+
});
|
|
115
|
+
nucleus.setInternalContext(internalScope);
|
|
116
|
+
|
|
117
|
+
const getTool = createInstrumentedToolGetter({
|
|
118
|
+
taskId,
|
|
119
|
+
capability: capabilityName,
|
|
120
|
+
toolRegistry,
|
|
121
|
+
ledger: this.options.ledger,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const runContext: RunContext = {
|
|
125
|
+
goal: this.options.goal,
|
|
126
|
+
context: state.context,
|
|
127
|
+
outputs: Object.fromEntries(state.outputs),
|
|
128
|
+
metrics: { costUsd: 0, elapsedSec: 0 },
|
|
129
|
+
getTool,
|
|
130
|
+
getCapabilityRegistry: () => capabilityRegistry,
|
|
131
|
+
stream,
|
|
132
|
+
nucleus,
|
|
133
|
+
internalContext: internalScope,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const preflight = await nucleus.preflight();
|
|
137
|
+
if (preflight.status === 'NEEDS_CONTEXT') {
|
|
138
|
+
throw new Error(
|
|
139
|
+
`Task ${taskId} requires additional context retrieval: ${preflight.retrievalDirectives.join(', ')}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Policy pre-check
|
|
144
|
+
if (policy) {
|
|
145
|
+
const policyInput = task.policyInput?.(runContext, taskSpec.input || state.input) || {};
|
|
146
|
+
|
|
147
|
+
const decision = await policy.evaluate('task.pre', {
|
|
148
|
+
action: taskSpec.capability,
|
|
149
|
+
input: policyInput,
|
|
150
|
+
context: state.context,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (!decision.allow) {
|
|
154
|
+
throw new Error(`Policy denied execution of ${taskSpec.capability}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Execute task
|
|
159
|
+
stream?.emit('task', { taskId, status: 'started' });
|
|
160
|
+
|
|
161
|
+
const output = await task.execute(runContext, taskSpec.input || state.input);
|
|
162
|
+
|
|
163
|
+
// Update outputs map
|
|
164
|
+
const newOutputs = new Map(state.outputs);
|
|
165
|
+
newOutputs.set(taskId, output);
|
|
166
|
+
|
|
167
|
+
stream?.emit('task', { taskId, status: 'completed', output });
|
|
168
|
+
|
|
169
|
+
// Log to ledger
|
|
170
|
+
if (ledger) {
|
|
171
|
+
ledger.append('TASK_END', { taskId, capability: taskSpec.capability });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const postcheck = await nucleus.postcheck(output);
|
|
175
|
+
if (postcheck.status === 'NEEDS_COMPENSATION' || postcheck.status === 'ESCALATE') {
|
|
176
|
+
throw new Error(`Task ${taskId} postcheck failed: ${postcheck.reason}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
taskId,
|
|
181
|
+
output,
|
|
182
|
+
outputs: newOutputs,
|
|
183
|
+
};
|
|
184
|
+
} catch (error) {
|
|
185
|
+
stream?.emit('task', { taskId, status: 'failed', error });
|
|
186
|
+
|
|
187
|
+
if (ledger) {
|
|
188
|
+
ledger.append('ERROR', { taskId, error: String(error) });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
taskId,
|
|
193
|
+
error: error as Error,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Create guard evaluator for conditional edges
|
|
201
|
+
*/
|
|
202
|
+
private createGuardEvaluator(guard?: string) {
|
|
203
|
+
if (!guard) {
|
|
204
|
+
return () => true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return (state: GraphState): boolean => {
|
|
208
|
+
try {
|
|
209
|
+
// Simple guard evaluation
|
|
210
|
+
const func = new Function('state', 'outputs', `return ${guard}`);
|
|
211
|
+
return func(state, Object.fromEntries(state.outputs));
|
|
212
|
+
} catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Build LangGraph structure
|
|
220
|
+
*
|
|
221
|
+
* Returns a configuration object that can be used with LangGraph's StateGraph
|
|
222
|
+
*/
|
|
223
|
+
buildGraph(): {
|
|
224
|
+
nodes: Map<string, (state: GraphState) => Promise<Partial<GraphState>>>;
|
|
225
|
+
edges: Array<{ from: string; to: string; condition?: (state: GraphState) => boolean }>;
|
|
226
|
+
entryPoint: string;
|
|
227
|
+
} {
|
|
228
|
+
const { plan } = this.options;
|
|
229
|
+
const nodes = new Map<string, (state: GraphState) => Promise<Partial<GraphState>>>();
|
|
230
|
+
const edges: Array<{ from: string; to: string; condition?: (state: GraphState) => boolean }> = [];
|
|
231
|
+
|
|
232
|
+
// Create nodes for each task
|
|
233
|
+
for (const task of plan.tasks) {
|
|
234
|
+
nodes.set(task.id, this.createNodeFunction(task.id));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Create edges
|
|
238
|
+
for (const edge of plan.edges) {
|
|
239
|
+
edges.push({
|
|
240
|
+
from: edge.from,
|
|
241
|
+
to: edge.to,
|
|
242
|
+
condition: edge.guard ? this.createGuardEvaluator(edge.guard) : undefined,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Find entry point (task with no incoming edges)
|
|
247
|
+
const hasIncoming = new Set(plan.edges.map((e) => e.to));
|
|
248
|
+
const entryPoint = plan.tasks.find((t) => !hasIncoming.has(t.id))?.id || plan.tasks[0]?.id;
|
|
249
|
+
|
|
250
|
+
if (!entryPoint) {
|
|
251
|
+
throw new Error('No entry point found in plan');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { nodes, edges, entryPoint };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Execute the plan using LangGraph (if available)
|
|
259
|
+
*
|
|
260
|
+
* Note: This is a simplified implementation. In practice, you would use
|
|
261
|
+
* LangGraph's StateGraph API directly with the graph structure.
|
|
262
|
+
*/
|
|
263
|
+
async execute(): Promise<{ outputsByTask: Record<string, any>; ledger: readonly any[] }> {
|
|
264
|
+
const { nodes, edges, entryPoint } = this.buildGraph();
|
|
265
|
+
|
|
266
|
+
// Initialize state
|
|
267
|
+
const state: GraphState = {
|
|
268
|
+
taskId: entryPoint,
|
|
269
|
+
input: {},
|
|
270
|
+
context: this.options.context,
|
|
271
|
+
outputs: new Map(),
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// Simple sequential execution based on edges
|
|
275
|
+
// In a real implementation, this would use LangGraph's execution engine
|
|
276
|
+
let currentTaskId: string | null = entryPoint;
|
|
277
|
+
const visited = new Set<string>();
|
|
278
|
+
|
|
279
|
+
while (currentTaskId && !visited.has(currentTaskId)) {
|
|
280
|
+
visited.add(currentTaskId);
|
|
281
|
+
|
|
282
|
+
const nodeFunc = nodes.get(currentTaskId);
|
|
283
|
+
if (!nodeFunc) break;
|
|
284
|
+
|
|
285
|
+
const result = await nodeFunc(state);
|
|
286
|
+
Object.assign(state, result);
|
|
287
|
+
|
|
288
|
+
// Find next task
|
|
289
|
+
const outgoingEdges = edges.filter((e) => e.from === currentTaskId);
|
|
290
|
+
currentTaskId = null;
|
|
291
|
+
|
|
292
|
+
for (const edge of outgoingEdges) {
|
|
293
|
+
if (!edge.condition || edge.condition(state)) {
|
|
294
|
+
currentTaskId = edge.to;
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
outputsByTask: Object.fromEntries(state.outputs),
|
|
302
|
+
ledger: this.options.ledger?.getEntries() || [],
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Helper function to create a LangGraph adapter
|
|
309
|
+
*/
|
|
310
|
+
export function asLangGraph(options: LangGraphAdapterOptions): LangGraphAdapter {
|
|
311
|
+
return new LangGraphAdapter(options);
|
|
312
|
+
}
|