@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/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
@@ -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
@@ -0,0 +1,3 @@
1
+ // Framework adapters for ACM
2
+ export { LangGraphAdapter, asLangGraph, type LangGraphAdapterOptions, type GraphState } from './langgraph.js';
3
+ export { MSAgentFrameworkAdapter, wrapAgentNodes, type MSAgentFrameworkAdapterOptions, type ActivityState } from './msaf.js';
@@ -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
+ }