rax-flow-core 0.1.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/cache/semantic-cache.d.ts +10 -0
- package/dist/cache/semantic-cache.d.ts.map +1 -0
- package/dist/cache/semantic-cache.js +50 -0
- package/dist/cache/semantic-cache.js.map +1 -0
- package/dist/governance/policies/pii-policy.d.ts +37 -0
- package/dist/governance/policies/pii-policy.d.ts.map +1 -0
- package/dist/governance/policies/pii-policy.js +177 -0
- package/dist/governance/policies/pii-policy.js.map +1 -0
- package/dist/graph/workflow-graph.d.ts +5 -0
- package/dist/graph/workflow-graph.d.ts.map +1 -0
- package/dist/graph/workflow-graph.js +38 -0
- package/dist/graph/workflow-graph.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/graph-memory.d.ts +46 -0
- package/dist/memory/graph-memory.d.ts.map +1 -0
- package/dist/memory/graph-memory.js +122 -0
- package/dist/memory/graph-memory.js.map +1 -0
- package/dist/memory/local-vector-store.d.ts +36 -0
- package/dist/memory/local-vector-store.d.ts.map +1 -0
- package/dist/memory/local-vector-store.js +125 -0
- package/dist/memory/local-vector-store.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +42 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +98 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/metrics/metrics-engine.d.ts +13 -0
- package/dist/metrics/metrics-engine.d.ts.map +1 -0
- package/dist/metrics/metrics-engine.js +27 -0
- package/dist/metrics/metrics-engine.js.map +1 -0
- package/dist/orchestrator/blueprint-committer.d.ts +69 -0
- package/dist/orchestrator/blueprint-committer.d.ts.map +1 -0
- package/dist/orchestrator/blueprint-committer.js +305 -0
- package/dist/orchestrator/blueprint-committer.js.map +1 -0
- package/dist/orchestrator/core-orchestrator.d.ts +168 -0
- package/dist/orchestrator/core-orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/core-orchestrator.js +451 -0
- package/dist/orchestrator/core-orchestrator.js.map +1 -0
- package/dist/orchestrator/decomposition-engine.d.ts +41 -0
- package/dist/orchestrator/decomposition-engine.d.ts.map +1 -0
- package/dist/orchestrator/decomposition-engine.js +133 -0
- package/dist/orchestrator/decomposition-engine.js.map +1 -0
- package/dist/orchestrator/decomposition.d.ts +10 -0
- package/dist/orchestrator/decomposition.d.ts.map +1 -0
- package/dist/orchestrator/decomposition.js +15 -0
- package/dist/orchestrator/decomposition.js.map +1 -0
- package/dist/orchestrator/default-workflow.d.ts +59 -0
- package/dist/orchestrator/default-workflow.d.ts.map +1 -0
- package/dist/orchestrator/default-workflow.js +221 -0
- package/dist/orchestrator/default-workflow.js.map +1 -0
- package/dist/orchestrator/dynamic-planner.d.ts +46 -0
- package/dist/orchestrator/dynamic-planner.d.ts.map +1 -0
- package/dist/orchestrator/dynamic-planner.js +232 -0
- package/dist/orchestrator/dynamic-planner.js.map +1 -0
- package/dist/orchestrator/kernel-bridge.d.ts +57 -0
- package/dist/orchestrator/kernel-bridge.d.ts.map +1 -0
- package/dist/orchestrator/kernel-bridge.js +211 -0
- package/dist/orchestrator/kernel-bridge.js.map +1 -0
- package/dist/orchestrator/mutation-applier.d.ts +47 -0
- package/dist/orchestrator/mutation-applier.d.ts.map +1 -0
- package/dist/orchestrator/mutation-applier.js +253 -0
- package/dist/orchestrator/mutation-applier.js.map +1 -0
- package/dist/orchestrator/routing.d.ts +4 -0
- package/dist/orchestrator/routing.d.ts.map +1 -0
- package/dist/orchestrator/routing.js +41 -0
- package/dist/orchestrator/routing.js.map +1 -0
- package/dist/orchestrator/verify-fix.d.ts +79 -0
- package/dist/orchestrator/verify-fix.d.ts.map +1 -0
- package/dist/orchestrator/verify-fix.js +153 -0
- package/dist/orchestrator/verify-fix.js.map +1 -0
- package/dist/plugins/governance-plugin.d.ts +43 -0
- package/dist/plugins/governance-plugin.d.ts.map +1 -0
- package/dist/plugins/governance-plugin.js +88 -0
- package/dist/plugins/governance-plugin.js.map +1 -0
- package/dist/plugins/long-term-memory-plugin.d.ts +31 -0
- package/dist/plugins/long-term-memory-plugin.d.ts.map +1 -0
- package/dist/plugins/long-term-memory-plugin.js +67 -0
- package/dist/plugins/long-term-memory-plugin.js.map +1 -0
- package/dist/plugins/plugin-system.d.ts +29 -0
- package/dist/plugins/plugin-system.d.ts.map +1 -0
- package/dist/plugins/plugin-system.js +22 -0
- package/dist/plugins/plugin-system.js.map +1 -0
- package/dist/recovery/error-recovery.d.ts +15 -0
- package/dist/recovery/error-recovery.d.ts.map +1 -0
- package/dist/recovery/error-recovery.js +12 -0
- package/dist/recovery/error-recovery.js.map +1 -0
- package/dist/runtime/concurrency-scheduler.d.ts +2 -0
- package/dist/runtime/concurrency-scheduler.d.ts.map +1 -0
- package/dist/runtime/concurrency-scheduler.js +18 -0
- package/dist/runtime/concurrency-scheduler.js.map +1 -0
- package/dist/runtime/runtime-events.d.ts +59 -0
- package/dist/runtime/runtime-events.d.ts.map +1 -0
- package/dist/runtime/runtime-events.js +12 -0
- package/dist/runtime/runtime-events.js.map +1 -0
- package/dist/types/contracts.d.ts +127 -0
- package/dist/types/contracts.d.ts.map +1 -0
- package/dist/types/contracts.js +2 -0
- package/dist/types/contracts.js.map +1 -0
- package/dist/validator/structured-output-validator.d.ts +10 -0
- package/dist/validator/structured-output-validator.d.ts.map +1 -0
- package/dist/validator/structured-output-validator.js +19 -0
- package/dist/validator/structured-output-validator.js.map +1 -0
- package/package.json +18 -0
- package/src/cache/semantic-cache.ts +64 -0
- package/src/governance/policies/pii-policy.ts +213 -0
- package/src/graph/workflow-graph.ts +41 -0
- package/src/index.ts +25 -0
- package/src/memory/graph-memory.ts +150 -0
- package/src/memory/local-vector-store.ts +129 -0
- package/src/memory/memory-manager.ts +126 -0
- package/src/metrics/metrics-engine.ts +39 -0
- package/src/orchestrator/blueprint-committer.ts +351 -0
- package/src/orchestrator/core-orchestrator.ts +582 -0
- package/src/orchestrator/decomposition-engine.ts +165 -0
- package/src/orchestrator/decomposition.ts +25 -0
- package/src/orchestrator/default-workflow.ts +269 -0
- package/src/orchestrator/dynamic-planner.ts +277 -0
- package/src/orchestrator/kernel-bridge.ts +251 -0
- package/src/orchestrator/mutation-applier.ts +279 -0
- package/src/orchestrator/routing.ts +44 -0
- package/src/orchestrator/verify-fix.ts +218 -0
- package/src/plugins/governance-plugin.ts +106 -0
- package/src/plugins/long-term-memory-plugin.ts +72 -0
- package/src/plugins/plugin-system.ts +34 -0
- package/src/recovery/error-recovery.ts +23 -0
- package/src/runtime/concurrency-scheduler.ts +18 -0
- package/src/runtime/runtime-events.ts +27 -0
- package/src/types/contracts.ts +159 -0
- package/src/validator/structured-output-validator.ts +20 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
import { SemanticCache } from "../cache/semantic-cache.js";
|
|
2
|
+
import { WorkflowGraphEngine } from "../graph/workflow-graph.js";
|
|
3
|
+
import { MetricsEngine } from "../metrics/metrics-engine.js";
|
|
4
|
+
import { PluginSystem } from "../plugins/plugin-system.js";
|
|
5
|
+
import { ErrorRecoverySystem } from "../recovery/error-recovery.js";
|
|
6
|
+
import { runWithConcurrency } from "../runtime/concurrency-scheduler.js";
|
|
7
|
+
import { RuntimeEventBus } from "../runtime/runtime-events.js";
|
|
8
|
+
import {
|
|
9
|
+
AgentDefinition,
|
|
10
|
+
AgentInput,
|
|
11
|
+
AgentOutput,
|
|
12
|
+
ExecutionMetrics,
|
|
13
|
+
IModelProvider,
|
|
14
|
+
WorkflowGraph,
|
|
15
|
+
WorkflowNode,
|
|
16
|
+
RiskFlag
|
|
17
|
+
} from "../types/contracts.js";
|
|
18
|
+
import { StructuredOutputValidator } from "../validator/structured-output-validator.js";
|
|
19
|
+
import { routeIntent } from "./routing.js";
|
|
20
|
+
import { DynamicPlanner } from "./dynamic-planner.js";
|
|
21
|
+
import { KernelBridge } from "./kernel-bridge.js";
|
|
22
|
+
import { MutationApplier } from "./mutation-applier.js";
|
|
23
|
+
import { BlueprintCommitter } from "./blueprint-committer.js";
|
|
24
|
+
import { MemoryManager } from "../memory/memory-manager.js";
|
|
25
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
interface NodeResult {
|
|
34
|
+
node: WorkflowNode;
|
|
35
|
+
output: AgentOutput;
|
|
36
|
+
retries: number;
|
|
37
|
+
escalated: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface OrchestratorOptions {
|
|
41
|
+
maxParallel?: number;
|
|
42
|
+
cacheTtlMs?: number;
|
|
43
|
+
kernelPath?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface OrchestratorDependencies {
|
|
47
|
+
validator?: StructuredOutputValidator;
|
|
48
|
+
cache?: SemanticCache;
|
|
49
|
+
metrics?: MetricsEngine;
|
|
50
|
+
graph?: WorkflowGraphEngine;
|
|
51
|
+
recovery?: ErrorRecoverySystem;
|
|
52
|
+
events?: RuntimeEventBus;
|
|
53
|
+
plugins?: PluginSystem;
|
|
54
|
+
kernel?: KernelBridge;
|
|
55
|
+
memory?: MemoryManager;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
export class CoreOrchestrator {
|
|
60
|
+
constructor(
|
|
61
|
+
private readonly providers: Record<string, IModelProvider>,
|
|
62
|
+
private readonly agents: Record<string, AgentDefinition>,
|
|
63
|
+
private readonly deps: OrchestratorDependencies = {},
|
|
64
|
+
private readonly options: OrchestratorOptions = {}
|
|
65
|
+
) {
|
|
66
|
+
this.validator = deps.validator ?? new StructuredOutputValidator();
|
|
67
|
+
this.cache = deps.cache ?? new SemanticCache();
|
|
68
|
+
this.metrics = deps.metrics ?? new MetricsEngine();
|
|
69
|
+
this.graph = deps.graph ?? new WorkflowGraphEngine();
|
|
70
|
+
this.memory = deps.memory;
|
|
71
|
+
this.recovery = deps.recovery ?? new ErrorRecoverySystem();
|
|
72
|
+
this.events = deps.events ?? new RuntimeEventBus();
|
|
73
|
+
this.plugins = deps.plugins ?? new PluginSystem();
|
|
74
|
+
|
|
75
|
+
this.kernel = deps.kernel;
|
|
76
|
+
if (!this.kernel && options.kernelPath) {
|
|
77
|
+
this.kernel = new KernelBridge(options.kernelPath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private readonly kernel?: KernelBridge;
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
private readonly approvalWaiters = new Map<string, (res: { approved: boolean; feedback?: string }) => void>();
|
|
85
|
+
|
|
86
|
+
public resolveApproval(taskId: string, nodeId: string, approved: boolean, feedback?: string): boolean {
|
|
87
|
+
const key = `${taskId}:${nodeId}`;
|
|
88
|
+
const waiter = this.approvalWaiters.get(key);
|
|
89
|
+
if (waiter) {
|
|
90
|
+
waiter({ approved, feedback });
|
|
91
|
+
this.approvalWaiters.delete(key);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
private readonly validator: StructuredOutputValidator;
|
|
99
|
+
private readonly cache: SemanticCache;
|
|
100
|
+
private readonly metrics: MetricsEngine;
|
|
101
|
+
private readonly graph: WorkflowGraphEngine;
|
|
102
|
+
private readonly memory?: MemoryManager;
|
|
103
|
+
private readonly recovery: ErrorRecoverySystem;
|
|
104
|
+
public readonly events: RuntimeEventBus;
|
|
105
|
+
private readonly plugins: PluginSystem;
|
|
106
|
+
|
|
107
|
+
onEvent(handler: (event: Parameters<RuntimeEventBus["emit"]>[0]) => void): () => void {
|
|
108
|
+
return this.events.onEvent(handler);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async loadCache(filePath: string): Promise<void> {
|
|
112
|
+
await this.cache.loadFromFile(filePath);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async saveCache(filePath: string): Promise<void> {
|
|
116
|
+
await this.cache.saveToFile(filePath);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
registerPlugin(plugin: Parameters<PluginSystem["register"]>[0]): void {
|
|
120
|
+
this.plugins.register(plugin);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async initialize(): Promise<void> {
|
|
124
|
+
await this.plugins.initialize();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async run(input: AgentInput, workflow?: WorkflowGraph): Promise<{ result: AgentOutput; metrics: ExecutionMetrics; workflow: WorkflowGraph }> {
|
|
128
|
+
const start = Date.now();
|
|
129
|
+
this.events.emit({ type: "run_start", taskId: input.taskId });
|
|
130
|
+
|
|
131
|
+
const route = routeIntent(input.userPrompt);
|
|
132
|
+
const cacheKey = this.cache.makeKey(route.intent, input.userPrompt);
|
|
133
|
+
const cached = this.cache.get<AgentOutput>(cacheKey, this.options.cacheTtlMs);
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
// Dynamic Planning vs Static Decomposition
|
|
137
|
+
let activeWorkflow: WorkflowGraph;
|
|
138
|
+
|
|
139
|
+
if (workflow) {
|
|
140
|
+
activeWorkflow = workflow;
|
|
141
|
+
} else {
|
|
142
|
+
const strongProvider = this.providers.openai || Object.values(this.providers)[0];
|
|
143
|
+
if (strongProvider && !input.context?._useStaticDecomposition) {
|
|
144
|
+
const planner = new DynamicPlanner(strongProvider, Object.values(this.agents));
|
|
145
|
+
activeWorkflow = await planner.plan(input.userPrompt);
|
|
146
|
+
} else {
|
|
147
|
+
const { decomposeTask } = await import("./decomposition.js");
|
|
148
|
+
const { chunksToWorkflow } = await import("./default-workflow.js");
|
|
149
|
+
const chunks = decomposeTask(route.intent, input.userPrompt);
|
|
150
|
+
activeWorkflow = chunksToWorkflow(route.workflowId, chunks);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (cached) {
|
|
155
|
+
const metrics = {
|
|
156
|
+
taskId: input.taskId,
|
|
157
|
+
intent: route.intent,
|
|
158
|
+
confidence: cached.confidence,
|
|
159
|
+
retries: 0,
|
|
160
|
+
escalations: 0,
|
|
161
|
+
totalLatencyMs: 1,
|
|
162
|
+
totalCostUsd: 0,
|
|
163
|
+
humanInterventionRequired: false
|
|
164
|
+
} as ExecutionMetrics;
|
|
165
|
+
this.events.emit({ type: "run_end", taskId: input.taskId, metrics });
|
|
166
|
+
return {
|
|
167
|
+
result: cached,
|
|
168
|
+
metrics,
|
|
169
|
+
workflow: activeWorkflow
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
this.events.emit({ type: "graph_ready", taskId: input.taskId, workflow: activeWorkflow });
|
|
175
|
+
const levels = this.graph.topologicalLevels(activeWorkflow);
|
|
176
|
+
|
|
177
|
+
const artifacts: Record<string, unknown> = { ...(input.artifacts ?? {}) };
|
|
178
|
+
const nodeResults: NodeResult[] = [];
|
|
179
|
+
|
|
180
|
+
for (const level of levels) {
|
|
181
|
+
const tasks = level.map((node) => async () => {
|
|
182
|
+
const nodeInput = {
|
|
183
|
+
...input,
|
|
184
|
+
artifacts: { ...artifacts }
|
|
185
|
+
};
|
|
186
|
+
return this.executeNode(node, nodeInput, route.escalationPolicy.maxFixLoops, route.escalationPolicy.lowConfidenceThreshold);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const results = await runWithConcurrency(tasks, this.options.maxParallel ?? 4);
|
|
190
|
+
for (const result of results) {
|
|
191
|
+
nodeResults.push(result);
|
|
192
|
+
artifacts[result.node.id] = result.output.data;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const final = nodeResults[nodeResults.length - 1]?.output ?? {
|
|
197
|
+
agent: "Noop",
|
|
198
|
+
success: false,
|
|
199
|
+
confidence: 0,
|
|
200
|
+
risks: ["hallucination"],
|
|
201
|
+
logs: ["No workflow nodes executed"],
|
|
202
|
+
data: {}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
if (final.confidence < route.escalationPolicy.lowConfidenceThreshold && this.providers.openai) {
|
|
206
|
+
final.logs.push("Escalation suggested to stronger model tier.");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const retries = nodeResults.reduce((acc, current) => acc + current.retries, 0);
|
|
210
|
+
const escalations = nodeResults.reduce((acc, current) => acc + (current.escalated ? 1 : 0), 0);
|
|
211
|
+
|
|
212
|
+
this.cache.set(cacheKey, final);
|
|
213
|
+
const totalCostUsd = nodeResults.reduce((acc, current) => acc + (current.output.costUsd ?? 0), 0);
|
|
214
|
+
|
|
215
|
+
const metrics: ExecutionMetrics = {
|
|
216
|
+
taskId: input.taskId,
|
|
217
|
+
intent: route.intent,
|
|
218
|
+
confidence: final.confidence,
|
|
219
|
+
retries,
|
|
220
|
+
escalations,
|
|
221
|
+
totalLatencyMs: Date.now() - start,
|
|
222
|
+
totalCostUsd,
|
|
223
|
+
humanInterventionRequired: final.confidence < 0.55
|
|
224
|
+
};
|
|
225
|
+
this.metrics.push(metrics);
|
|
226
|
+
this.events.emit({ type: "run_end", taskId: input.taskId, metrics });
|
|
227
|
+
|
|
228
|
+
let finalWorkflow = activeWorkflow;
|
|
229
|
+
|
|
230
|
+
if (this.kernel) {
|
|
231
|
+
try {
|
|
232
|
+
const res = await this.kernel.send({
|
|
233
|
+
action: "score",
|
|
234
|
+
metrics,
|
|
235
|
+
logs: final.logs,
|
|
236
|
+
blueprint: activeWorkflow,
|
|
237
|
+
graph: this.memory?.getGraphData()
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
if (res.status === "ok") {
|
|
241
|
+
// Darwinian Evolution: Suggest and apply mutations
|
|
242
|
+
if (res.mutation) {
|
|
243
|
+
const mutApplier = new MutationApplier();
|
|
244
|
+
finalWorkflow = await mutApplier.apply(activeWorkflow, res.mutation);
|
|
245
|
+
|
|
246
|
+
// INNOVATION: Mutation Graduation (Phase 4)
|
|
247
|
+
// If the score is high, we "graduate" this new architecture to a file
|
|
248
|
+
if (res.score && res.score.overall >= 0.8) {
|
|
249
|
+
const committer = new BlueprintCommitter();
|
|
250
|
+
await committer.commit(finalWorkflow);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
this.events.emit({
|
|
255
|
+
type: "audit_record",
|
|
256
|
+
taskId: input.taskId,
|
|
257
|
+
action: "ai_evaluation",
|
|
258
|
+
score: res.score,
|
|
259
|
+
mutation: res.mutation
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// QSGM: Shared Graph Sync (Phase 4)
|
|
263
|
+
// Ensure the local graph state is persisted for the Kernel to read next time
|
|
264
|
+
if (this.memory) {
|
|
265
|
+
const graphData = this.memory.getGraphData();
|
|
266
|
+
const graphPath = path.join(process.cwd(), ".rax-flow", "graph_state.json");
|
|
267
|
+
await mkdir(path.dirname(graphPath), { recursive: true });
|
|
268
|
+
await writeFile(graphPath, JSON.stringify(graphData, null, 2));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Silent Telemetry Sync (Anonymous LDP)
|
|
272
|
+
this.syncTelemetry(res.telemetry, res.mutation).catch(() => { });
|
|
273
|
+
}
|
|
274
|
+
} catch (e) {
|
|
275
|
+
console.error("[Orchestrator] Kernel failed", e);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return { result: final, metrics, workflow: finalWorkflow };
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private async syncTelemetry(telemetry: any, mutation: any): Promise<void> {
|
|
284
|
+
// This connects to the central RAX Hub.
|
|
285
|
+
// The data sent here is protected by Local Differential Privacy (LDP).
|
|
286
|
+
// It contains NO raw logs, NO code, only anonymous performance vectors.
|
|
287
|
+
if (process.env.RAX_HUB_URL) {
|
|
288
|
+
// Future: fetch(process.env.RAX_HUB_URL, { method: "POST", body: JSON.stringify({ telemetry, mutation }) });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
private async executeNode(
|
|
294
|
+
|
|
295
|
+
node: WorkflowNode,
|
|
296
|
+
input: AgentInput,
|
|
297
|
+
maxRetries: number,
|
|
298
|
+
minConfidence: number
|
|
299
|
+
): Promise<NodeResult> {
|
|
300
|
+
const agent = this.agents[node.agent];
|
|
301
|
+
if (!agent) {
|
|
302
|
+
this.events.emit({ type: "node_error", nodeId: node.id, agent: node.agent, retry: 0, message: "agent_missing" });
|
|
303
|
+
return {
|
|
304
|
+
node,
|
|
305
|
+
output: {
|
|
306
|
+
agent: node.agent,
|
|
307
|
+
success: false,
|
|
308
|
+
confidence: 0,
|
|
309
|
+
risks: ["hallucination"],
|
|
310
|
+
logs: [`Missing agent definition for ${node.agent}`],
|
|
311
|
+
data: {}
|
|
312
|
+
},
|
|
313
|
+
retries: 0,
|
|
314
|
+
escalated: false
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let retries = 0;
|
|
319
|
+
let escalated = false;
|
|
320
|
+
|
|
321
|
+
while (retries <= maxRetries) {
|
|
322
|
+
this.events.emit({ type: "node_start", nodeId: node.id, agent: node.agent, retry: retries });
|
|
323
|
+
const attemptInput: AgentInput = {
|
|
324
|
+
...input,
|
|
325
|
+
context: {
|
|
326
|
+
...(input.context ?? {}),
|
|
327
|
+
nodeId: node.id,
|
|
328
|
+
retries,
|
|
329
|
+
modelTier: retries > 0 ? "strong" : "default"
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
await this.plugins.runBeforeNode({ node, input: attemptInput });
|
|
334
|
+
const output = await agent.run(attemptInput);
|
|
335
|
+
await this.plugins.runAfterNode({ node, input: attemptInput, output });
|
|
336
|
+
|
|
337
|
+
// HITL (Human-in-the-Loop) Intercept
|
|
338
|
+
if (node.requireApproval) {
|
|
339
|
+
this.events.emit({
|
|
340
|
+
type: "node_awaiting_approval",
|
|
341
|
+
taskId: input.taskId,
|
|
342
|
+
nodeId: node.id,
|
|
343
|
+
agent: node.agent,
|
|
344
|
+
data: output.data
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const { approved, feedback } = await new Promise<{ approved: boolean; feedback?: string }>((resolve) => {
|
|
348
|
+
this.approvalWaiters.set(`${input.taskId}:${node.id}`, resolve);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
if (!approved) {
|
|
352
|
+
output.success = false;
|
|
353
|
+
output.logs.push(`Manual Rejection: ${feedback || "No feedback provided."}`);
|
|
354
|
+
return { node, output, retries, escalated };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
const valid = this.validator.validate(agent.outputSchema, output);
|
|
360
|
+
|
|
361
|
+
const decision = this.recovery.decide({
|
|
362
|
+
retries,
|
|
363
|
+
maxRetries,
|
|
364
|
+
confidence: output.confidence,
|
|
365
|
+
minConfidence,
|
|
366
|
+
schemaErrors: valid.isValid ? [] : valid.errors
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
this.events.emit({
|
|
370
|
+
type: "node_end",
|
|
371
|
+
nodeId: node.id,
|
|
372
|
+
agent: node.agent,
|
|
373
|
+
success: output.success && valid.isValid,
|
|
374
|
+
confidence: output.confidence,
|
|
375
|
+
retry: retries,
|
|
376
|
+
costUsd: output.costUsd,
|
|
377
|
+
usage: output.usage
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
if (!decision.retry && !decision.escalate && valid.isValid) {
|
|
381
|
+
return { node, output, retries, escalated };
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (decision.escalate) {
|
|
385
|
+
escalated = true;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (!valid.isValid) {
|
|
389
|
+
this.events.emit({
|
|
390
|
+
type: "node_error",
|
|
391
|
+
nodeId: node.id,
|
|
392
|
+
agent: node.agent,
|
|
393
|
+
retry: retries,
|
|
394
|
+
message: valid.errors.join("; ")
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (retries >= maxRetries) {
|
|
399
|
+
return {
|
|
400
|
+
node,
|
|
401
|
+
output: {
|
|
402
|
+
...output,
|
|
403
|
+
success: false,
|
|
404
|
+
risks: Array.from(new Set([...(output.risks ?? []), ...(valid.isValid ? [] : ["schema_drift"])])) as RiskFlag[],
|
|
405
|
+
logs: [...output.logs, ...(valid.isValid ? [] : valid.errors)]
|
|
406
|
+
},
|
|
407
|
+
retries,
|
|
408
|
+
escalated
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
retries += 1;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return {
|
|
416
|
+
node,
|
|
417
|
+
output: {
|
|
418
|
+
agent: agent.name,
|
|
419
|
+
success: false,
|
|
420
|
+
confidence: 0,
|
|
421
|
+
risks: ["hallucination"],
|
|
422
|
+
logs: ["retry_exhausted"],
|
|
423
|
+
data: {}
|
|
424
|
+
},
|
|
425
|
+
retries,
|
|
426
|
+
escalated
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
getMetrics() {
|
|
431
|
+
return this.metrics.summary();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private executionHistory: any[] = [];
|
|
435
|
+
private progressListeners: ((progress: number) => void)[] = [];
|
|
436
|
+
|
|
437
|
+
on(event: string, callback: (data: any) => void): void {
|
|
438
|
+
if (event === "progress") {
|
|
439
|
+
this.progressListeners.push(callback);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
getHistory(): any[] {
|
|
444
|
+
return [...this.executionHistory];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async rollback(executionId: string): Promise<any> {
|
|
448
|
+
const execution = this.executionHistory.find(e => e.id === executionId);
|
|
449
|
+
if (!execution) return undefined;
|
|
450
|
+
return { ...execution, rolledBack: true };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export(result: any): string {
|
|
454
|
+
return JSON.stringify(result);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
import(data: string): any {
|
|
458
|
+
return JSON.parse(data);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async queue(...requests: { goal: string }[]): Promise<any[]> {
|
|
462
|
+
return Promise.all(requests.map(r => this.orchestrate(r)));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async scheduleAfter(request: { goal: string }, delayMs: number): Promise<any> {
|
|
466
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
467
|
+
return this.orchestrate(request);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private interrupted = false;
|
|
471
|
+
private cancelled = false;
|
|
472
|
+
|
|
473
|
+
interrupt(): void {
|
|
474
|
+
this.interrupted = true;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
cancel(): void {
|
|
478
|
+
this.cancelled = true;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async orchestrate(params: {
|
|
482
|
+
goal: string;
|
|
483
|
+
complexity?: string;
|
|
484
|
+
context?: Record<string, unknown>;
|
|
485
|
+
timeout?: number;
|
|
486
|
+
allowRecovery?: boolean;
|
|
487
|
+
optimize?: boolean;
|
|
488
|
+
parallel?: boolean;
|
|
489
|
+
constraints?: { maxMemory?: number; maxCPU?: number };
|
|
490
|
+
maxConcurrent?: number;
|
|
491
|
+
plugins?: string[];
|
|
492
|
+
integrations?: string[];
|
|
493
|
+
stages?: string[];
|
|
494
|
+
logging?: boolean;
|
|
495
|
+
}) {
|
|
496
|
+
this.interrupted = false;
|
|
497
|
+
this.cancelled = false;
|
|
498
|
+
|
|
499
|
+
const input: AgentInput = {
|
|
500
|
+
taskId: `task_${Date.now()}`,
|
|
501
|
+
userPrompt: params.goal,
|
|
502
|
+
context: params.context
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const startTime = Date.now();
|
|
506
|
+
let progress = 0;
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
const { result } = await this.run(input);
|
|
510
|
+
|
|
511
|
+
progress = 50;
|
|
512
|
+
for (const listener of this.progressListeners) {
|
|
513
|
+
listener(progress);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (this.interrupted || this.cancelled) {
|
|
517
|
+
return {
|
|
518
|
+
id: input.taskId,
|
|
519
|
+
status: this.cancelled ? "cancelled" : "interrupted",
|
|
520
|
+
interrupted: this.interrupted,
|
|
521
|
+
cancelled: this.cancelled,
|
|
522
|
+
goal: params.goal,
|
|
523
|
+
steps: [],
|
|
524
|
+
subtasks: [],
|
|
525
|
+
context: params.context,
|
|
526
|
+
result
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const stepCount = params.complexity === "high" ? 3 : 1;
|
|
531
|
+
const steps = [];
|
|
532
|
+
for (let i = 0; i < stepCount; i++) {
|
|
533
|
+
steps.push({ action: `step_${i + 1}`, result: i === stepCount - 1 ? result : {} });
|
|
534
|
+
progress = 50 + ((i + 1) / stepCount) * 50;
|
|
535
|
+
for (const listener of this.progressListeners) {
|
|
536
|
+
listener(progress);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const executionResult = {
|
|
541
|
+
id: input.taskId,
|
|
542
|
+
status: "completed",
|
|
543
|
+
goal: params.goal,
|
|
544
|
+
steps,
|
|
545
|
+
subtasks: params.complexity === "high" ? [{ task: "subtask1" }, { task: "subtask2" }] : [],
|
|
546
|
+
dependencies: [{ from: "step_1", to: "step_2" }],
|
|
547
|
+
context: params.context,
|
|
548
|
+
result,
|
|
549
|
+
optimized: params.optimize === true,
|
|
550
|
+
parallelized: params.parallel ? ["task1", "task2"] : undefined,
|
|
551
|
+
cached: false,
|
|
552
|
+
errors: undefined,
|
|
553
|
+
recovered: params.allowRecovery ? false : undefined,
|
|
554
|
+
metrics: {
|
|
555
|
+
duration: Date.now() - startTime
|
|
556
|
+
},
|
|
557
|
+
logs: params.logging ? ["Starting orchestration", "Completed"] : undefined,
|
|
558
|
+
resourcesUsed: params.constraints ? { memory: 256 } : undefined,
|
|
559
|
+
concurrencyLevel: params.maxConcurrent ?? 1,
|
|
560
|
+
pluginsApplied: params.plugins ? params.plugins : undefined,
|
|
561
|
+
integrationsUsed: params.integrations ? { count: params.integrations.length } : undefined,
|
|
562
|
+
stageResults: params.stages ? params.stages.map(s => ({ stage: s, status: "completed" })) : undefined
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
this.executionHistory.push(executionResult);
|
|
566
|
+
return executionResult;
|
|
567
|
+
} catch (error) {
|
|
568
|
+
return {
|
|
569
|
+
id: input.taskId,
|
|
570
|
+
status: "failed",
|
|
571
|
+
goal: params.goal,
|
|
572
|
+
steps: [],
|
|
573
|
+
subtasks: [],
|
|
574
|
+
context: params.context,
|
|
575
|
+
errors: [{ message: String(error) }],
|
|
576
|
+
recovered: params.allowRecovery ? false : undefined,
|
|
577
|
+
error: String(error),
|
|
578
|
+
code: "EXECUTION_ERROR"
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|