confused-ai-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.
Files changed (114) hide show
  1. package/FEATURES.md +169 -0
  2. package/package.json +119 -0
  3. package/src/agent.ts +187 -0
  4. package/src/agentic/index.ts +87 -0
  5. package/src/agentic/runner.ts +386 -0
  6. package/src/agentic/types.ts +91 -0
  7. package/src/artifacts/artifact.ts +417 -0
  8. package/src/artifacts/index.ts +42 -0
  9. package/src/artifacts/media.ts +304 -0
  10. package/src/cli/index.ts +122 -0
  11. package/src/core/base-agent.ts +151 -0
  12. package/src/core/context-builder.ts +106 -0
  13. package/src/core/index.ts +8 -0
  14. package/src/core/schemas.ts +17 -0
  15. package/src/core/types.ts +158 -0
  16. package/src/create-agent.ts +309 -0
  17. package/src/debug-logger.ts +188 -0
  18. package/src/dx/agent.ts +88 -0
  19. package/src/dx/define-agent.ts +183 -0
  20. package/src/dx/dev-logger.ts +57 -0
  21. package/src/dx/index.ts +11 -0
  22. package/src/errors.ts +175 -0
  23. package/src/execution/engine.ts +522 -0
  24. package/src/execution/graph-builder.ts +362 -0
  25. package/src/execution/index.ts +8 -0
  26. package/src/execution/types.ts +257 -0
  27. package/src/execution/worker-pool.ts +308 -0
  28. package/src/extensions/index.ts +123 -0
  29. package/src/guardrails/allowlist.ts +155 -0
  30. package/src/guardrails/index.ts +17 -0
  31. package/src/guardrails/types.ts +159 -0
  32. package/src/guardrails/validator.ts +265 -0
  33. package/src/index.ts +74 -0
  34. package/src/knowledge/index.ts +5 -0
  35. package/src/knowledge/types.ts +52 -0
  36. package/src/learning/in-memory-store.ts +72 -0
  37. package/src/learning/index.ts +6 -0
  38. package/src/learning/types.ts +42 -0
  39. package/src/llm/cache.ts +300 -0
  40. package/src/llm/index.ts +22 -0
  41. package/src/llm/model-resolver.ts +81 -0
  42. package/src/llm/openai-provider.ts +313 -0
  43. package/src/llm/openrouter-provider.ts +29 -0
  44. package/src/llm/types.ts +131 -0
  45. package/src/memory/in-memory-store.ts +255 -0
  46. package/src/memory/index.ts +7 -0
  47. package/src/memory/types.ts +193 -0
  48. package/src/memory/vector-store.ts +251 -0
  49. package/src/observability/console-logger.ts +123 -0
  50. package/src/observability/index.ts +12 -0
  51. package/src/observability/metrics.ts +85 -0
  52. package/src/observability/otlp-exporter.ts +417 -0
  53. package/src/observability/tracer.ts +105 -0
  54. package/src/observability/types.ts +341 -0
  55. package/src/orchestration/agent-adapter.ts +33 -0
  56. package/src/orchestration/index.ts +34 -0
  57. package/src/orchestration/load-balancer.ts +151 -0
  58. package/src/orchestration/mcp-types.ts +59 -0
  59. package/src/orchestration/message-bus.ts +192 -0
  60. package/src/orchestration/orchestrator.ts +349 -0
  61. package/src/orchestration/pipeline.ts +66 -0
  62. package/src/orchestration/supervisor.ts +107 -0
  63. package/src/orchestration/swarm.ts +1099 -0
  64. package/src/orchestration/toolkit.ts +47 -0
  65. package/src/orchestration/types.ts +339 -0
  66. package/src/planner/classical-planner.ts +383 -0
  67. package/src/planner/index.ts +8 -0
  68. package/src/planner/llm-planner.ts +353 -0
  69. package/src/planner/types.ts +227 -0
  70. package/src/planner/validator.ts +297 -0
  71. package/src/production/circuit-breaker.ts +290 -0
  72. package/src/production/graceful-shutdown.ts +251 -0
  73. package/src/production/health.ts +333 -0
  74. package/src/production/index.ts +57 -0
  75. package/src/production/latency-eval.ts +62 -0
  76. package/src/production/rate-limiter.ts +287 -0
  77. package/src/production/resumable-stream.ts +289 -0
  78. package/src/production/types.ts +81 -0
  79. package/src/sdk/index.ts +374 -0
  80. package/src/session/db-driver.ts +50 -0
  81. package/src/session/in-memory-store.ts +235 -0
  82. package/src/session/index.ts +12 -0
  83. package/src/session/sql-store.ts +315 -0
  84. package/src/session/sqlite-store.ts +61 -0
  85. package/src/session/types.ts +153 -0
  86. package/src/tools/base-tool.ts +223 -0
  87. package/src/tools/browser-tool.ts +123 -0
  88. package/src/tools/calculator-tool.ts +265 -0
  89. package/src/tools/file-tools.ts +394 -0
  90. package/src/tools/github-tool.ts +432 -0
  91. package/src/tools/hackernews-tool.ts +187 -0
  92. package/src/tools/http-tool.ts +118 -0
  93. package/src/tools/index.ts +99 -0
  94. package/src/tools/jira-tool.ts +373 -0
  95. package/src/tools/notion-tool.ts +322 -0
  96. package/src/tools/openai-tool.ts +236 -0
  97. package/src/tools/registry.ts +131 -0
  98. package/src/tools/serpapi-tool.ts +234 -0
  99. package/src/tools/shell-tool.ts +118 -0
  100. package/src/tools/slack-tool.ts +327 -0
  101. package/src/tools/telegram-tool.ts +127 -0
  102. package/src/tools/types.ts +229 -0
  103. package/src/tools/websearch-tool.ts +335 -0
  104. package/src/tools/wikipedia-tool.ts +177 -0
  105. package/src/tools/yfinance-tool.ts +33 -0
  106. package/src/voice/index.ts +17 -0
  107. package/src/voice/voice-provider.ts +228 -0
  108. package/tests/artifact.test.ts +241 -0
  109. package/tests/circuit-breaker.test.ts +171 -0
  110. package/tests/health.test.ts +192 -0
  111. package/tests/llm-cache.test.ts +186 -0
  112. package/tests/rate-limiter.test.ts +161 -0
  113. package/tsconfig.json +29 -0
  114. package/vitest.config.ts +47 -0
@@ -0,0 +1,522 @@
1
+ /**
2
+ * Execution engine implementation
3
+ */
4
+
5
+ import {
6
+ ExecutionEngine,
7
+ ExecutionEngineConfig,
8
+ ExecutionOptions,
9
+ ExecutionStatus,
10
+ ExecutionState,
11
+ ExecutionProgress,
12
+ ExecutionEvent,
13
+ ExecutionEventType,
14
+ ExecutionEventHandler,
15
+ ExecutionGraph,
16
+ ExecutionNode,
17
+ ExecutionNodeStatus,
18
+ TaskExecutor,
19
+ ExecutionContext,
20
+ BackoffStrategy,
21
+ } from './types.js';
22
+ import {
23
+ Plan,
24
+ Task,
25
+ TaskResult,
26
+ TaskStatus,
27
+ PlanExecutionResult,
28
+ PlanExecutionStatus,
29
+ } from '../planner/types.js';
30
+ import type { EntityId } from '../core/types.js';
31
+ import { EventEmitter } from 'events';
32
+
33
+ /**
34
+ * Default execution configuration
35
+ */
36
+ const DEFAULT_CONFIG: Required<ExecutionEngineConfig> = {
37
+ maxConcurrency: 4,
38
+ defaultTimeoutMs: 30000,
39
+ enableParallelExecution: true,
40
+ workerPoolSize: 4,
41
+ retryPolicy: {
42
+ maxRetries: 3,
43
+ backoffStrategy: BackoffStrategy.EXPONENTIAL,
44
+ initialDelayMs: 1000,
45
+ maxDelayMs: 30000,
46
+ },
47
+ };
48
+
49
+ /**
50
+ * Execution engine implementation
51
+ */
52
+ export class ExecutionEngineImpl extends EventEmitter implements ExecutionEngine {
53
+ private config: Required<ExecutionEngineConfig>;
54
+ private executors: Map<string, TaskExecutor> = new Map();
55
+ private executions: Map<EntityId, ExecutionStatus> = new Map();
56
+ private runningExecutions: Map<EntityId, AbortController> = new Map();
57
+
58
+ constructor(config: Partial<ExecutionEngineConfig> = {}) {
59
+ super();
60
+ this.config = { ...DEFAULT_CONFIG, ...config };
61
+ }
62
+
63
+ async execute(plan: Plan, options: ExecutionOptions = {}): Promise<PlanExecutionResult> {
64
+ const executionId = options.executionId ?? this.generateId();
65
+ // timeoutMs is used for potential future timeout implementation
66
+ void (options.timeoutMs ?? this.config.defaultTimeoutMs);
67
+
68
+ // Create execution graph
69
+ const graph = this.buildExecutionGraph(plan);
70
+
71
+ // Initialize execution status
72
+ const status: ExecutionStatus = {
73
+ executionId,
74
+ planId: plan.id,
75
+ state: ExecutionState.PENDING,
76
+ progress: this.calculateProgress(graph),
77
+ currentTasks: [],
78
+ startedAt: new Date(),
79
+ };
80
+
81
+ this.executions.set(executionId, status);
82
+
83
+ // Create abort controller for cancellation
84
+ const abortController = new AbortController();
85
+ this.runningExecutions.set(executionId, abortController);
86
+
87
+ try {
88
+ // Update state to running
89
+ this.updateExecutionState(executionId, ExecutionState.RUNNING);
90
+ this.emitEvent('execution:start', executionId, { planId: plan.id });
91
+
92
+ // Execute the plan
93
+ const results = await this.executeGraph(
94
+ graph,
95
+ executionId,
96
+ abortController.signal,
97
+ options
98
+ );
99
+
100
+ // Determine final status
101
+ const failedTasks = Array.from(results.values()).filter(
102
+ r => r.status === TaskStatus.FAILED
103
+ );
104
+ const cancelledTasks = Array.from(results.values()).filter(
105
+ r => r.status === TaskStatus.CANCELLED
106
+ );
107
+
108
+ let finalStatus: PlanExecutionStatus;
109
+ if (cancelledTasks.length > 0) {
110
+ finalStatus = PlanExecutionStatus.CANCELLED;
111
+ } else if (failedTasks.length === 0) {
112
+ finalStatus = PlanExecutionStatus.COMPLETED;
113
+ } else if (failedTasks.length < results.size) {
114
+ finalStatus = PlanExecutionStatus.PARTIAL;
115
+ } else {
116
+ finalStatus = PlanExecutionStatus.FAILED;
117
+ }
118
+
119
+ const endTime = new Date();
120
+ const result: PlanExecutionResult = {
121
+ planId: plan.id,
122
+ status: finalStatus,
123
+ taskResults: results,
124
+ startedAt: status.startedAt,
125
+ completedAt: endTime,
126
+ totalExecutionTimeMs: endTime.getTime() - status.startedAt.getTime(),
127
+ };
128
+
129
+ // Update execution status
130
+ this.updateExecutionState(
131
+ executionId,
132
+ finalStatus === PlanExecutionStatus.COMPLETED
133
+ ? ExecutionState.COMPLETED
134
+ : ExecutionState.FAILED
135
+ );
136
+
137
+ this.emitEvent('execution:complete', executionId, { result });
138
+
139
+ return result;
140
+ } catch (error) {
141
+ this.updateExecutionState(executionId, ExecutionState.FAILED);
142
+ this.emitEvent('execution:fail', executionId, { error });
143
+
144
+ throw error;
145
+ } finally {
146
+ this.runningExecutions.delete(executionId);
147
+ }
148
+ }
149
+
150
+ async cancel(executionId: EntityId): Promise<boolean> {
151
+ const controller = this.runningExecutions.get(executionId);
152
+ if (!controller) {
153
+ return false;
154
+ }
155
+
156
+ controller.abort();
157
+ this.updateExecutionState(executionId, ExecutionState.CANCELLED);
158
+ this.emitEvent('execution:cancel', executionId, {});
159
+
160
+ return true;
161
+ }
162
+
163
+ getStatus(executionId: EntityId): ExecutionStatus | undefined {
164
+ return this.executions.get(executionId);
165
+ }
166
+
167
+ registerExecutor(executor: TaskExecutor): void {
168
+ const type = executor.constructor.name;
169
+ this.executors.set(type, executor);
170
+ }
171
+
172
+ on(event: ExecutionEventType, handler: ExecutionEventHandler): this {
173
+ super.on(event, handler);
174
+ return this;
175
+ }
176
+
177
+ off(event: ExecutionEventType, handler: ExecutionEventHandler): this {
178
+ super.off(event, handler);
179
+ return this;
180
+ }
181
+
182
+ /**
183
+ * Build execution graph from plan
184
+ */
185
+ private buildExecutionGraph(plan: Plan): ExecutionGraph {
186
+ const nodes = new Map<EntityId, ExecutionNode>();
187
+ const readyQueue: EntityId[] = [];
188
+
189
+ // Create nodes for all tasks
190
+ for (const task of plan.tasks) {
191
+ const node: ExecutionNode = {
192
+ task,
193
+ status: ExecutionNodeStatus.PENDING,
194
+ dependencies: new Set(task.dependencies),
195
+ dependents: new Set(),
196
+ };
197
+ nodes.set(task.id, node);
198
+
199
+ // Add to ready queue if no dependencies
200
+ if (task.dependencies.length === 0) {
201
+ readyQueue.push(task.id);
202
+ }
203
+ }
204
+
205
+ // Build reverse dependency map (dependents)
206
+ for (const [id, node] of nodes) {
207
+ for (const depId of node.dependencies) {
208
+ const depNode = nodes.get(depId);
209
+ if (depNode) {
210
+ depNode.dependents.add(id);
211
+ }
212
+ }
213
+ }
214
+
215
+ return {
216
+ planId: plan.id,
217
+ nodes,
218
+ readyQueue,
219
+ completedCount: 0,
220
+ failedCount: 0,
221
+ totalCount: plan.tasks.length,
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Execute the execution graph
227
+ */
228
+ private async executeGraph(
229
+ graph: ExecutionGraph,
230
+ executionId: EntityId,
231
+ abortSignal: AbortSignal,
232
+ options: ExecutionOptions
233
+ ): Promise<Map<EntityId, TaskResult>> {
234
+ const results = new Map<EntityId, TaskResult>();
235
+ const executing = new Set<Promise<void>>();
236
+
237
+ const processNode = async (nodeId: EntityId): Promise<void> => {
238
+ const node = graph.nodes.get(nodeId);
239
+ if (!node || abortSignal.aborted) {
240
+ return;
241
+ }
242
+
243
+ // Check if all dependencies are satisfied
244
+ for (const depId of node.dependencies) {
245
+ const depResult = results.get(depId);
246
+ if (!depResult || depResult.status === TaskStatus.FAILED) {
247
+ // Skip this task if dependency failed
248
+ const skipResult: TaskResult = {
249
+ taskId: nodeId,
250
+ status: TaskStatus.SKIPPED,
251
+ executionTimeMs: 0,
252
+ startedAt: new Date(),
253
+ };
254
+ results.set(nodeId, skipResult);
255
+ this.updateNodeStatus(graph, nodeId, ExecutionNodeStatus.CANCELLED);
256
+ return;
257
+ }
258
+ }
259
+
260
+ // Update status
261
+ this.updateNodeStatus(graph, nodeId, ExecutionNodeStatus.RUNNING);
262
+ this.emitEvent('task:start', executionId, { taskId: nodeId });
263
+
264
+ if (options.onTaskStart) {
265
+ options.onTaskStart(nodeId);
266
+ }
267
+
268
+ const startTime = new Date();
269
+
270
+ try {
271
+ // Find appropriate executor
272
+ const executor = this.findExecutor(node.task);
273
+ if (!executor) {
274
+ throw new Error(`No executor found for task: ${node.task.name}`);
275
+ }
276
+
277
+ // Create execution context
278
+ const context: ExecutionContext = {
279
+ executionId,
280
+ taskId: nodeId,
281
+ planId: graph.planId,
282
+ inputs: this.collectInputs(node.task, results),
283
+ sharedState: new Map(),
284
+ metadata: {
285
+ startedAt: startTime,
286
+ attemptNumber: 1,
287
+ },
288
+ };
289
+
290
+ // Execute task
291
+ const result = await executor.execute(node.task, context);
292
+
293
+ results.set(nodeId, result);
294
+
295
+ // Update status based on result
296
+ if (result.status === TaskStatus.COMPLETED) {
297
+ this.updateNodeStatus(graph, nodeId, ExecutionNodeStatus.COMPLETED);
298
+ this.emitEvent('task:complete', executionId, { taskId: nodeId, result });
299
+
300
+ if (options.onTaskComplete) {
301
+ options.onTaskComplete(nodeId, result);
302
+ }
303
+ } else {
304
+ this.updateNodeStatus(graph, nodeId, ExecutionNodeStatus.FAILED);
305
+ this.emitEvent('task:fail', executionId, { taskId: nodeId, result });
306
+
307
+ if (options.onTaskError) {
308
+ options.onTaskError(nodeId, new Error(result.error?.message ?? 'Task failed'));
309
+ }
310
+ }
311
+ } catch (error) {
312
+ const failedResult: TaskResult = {
313
+ taskId: nodeId,
314
+ status: TaskStatus.FAILED,
315
+ error: {
316
+ code: 'EXECUTION_ERROR',
317
+ message: error instanceof Error ? error.message : String(error),
318
+ retryable: true,
319
+ },
320
+ executionTimeMs: Date.now() - startTime.getTime(),
321
+ startedAt: startTime,
322
+ completedAt: new Date(),
323
+ };
324
+
325
+ results.set(nodeId, failedResult);
326
+ this.updateNodeStatus(graph, nodeId, ExecutionNodeStatus.FAILED);
327
+ this.emitEvent('task:fail', executionId, { taskId: nodeId, error });
328
+
329
+ if (options.onTaskError) {
330
+ options.onTaskError(nodeId, error instanceof Error ? error : new Error(String(error)));
331
+ }
332
+ }
333
+ };
334
+
335
+ // Process ready queue
336
+ while (graph.readyQueue.length > 0 || executing.size > 0) {
337
+ if (abortSignal.aborted) {
338
+ break;
339
+ }
340
+
341
+ // Start new tasks up to concurrency limit
342
+ while (
343
+ graph.readyQueue.length > 0 &&
344
+ executing.size < this.config.maxConcurrency
345
+ ) {
346
+ const nodeId = graph.readyQueue.shift()!;
347
+ const promise = processNode(nodeId).then(() => {
348
+ executing.delete(promise);
349
+
350
+ // Add dependents to ready queue
351
+ const node = graph.nodes.get(nodeId);
352
+ if (node) {
353
+ for (const dependentId of node.dependents) {
354
+ const dependent = graph.nodes.get(dependentId);
355
+ if (dependent && dependent.status === ExecutionNodeStatus.PENDING) {
356
+ // Check if all dependencies are completed
357
+ const allDepsCompleted = Array.from(dependent.dependencies).every(
358
+ depId => {
359
+ const depNode = graph.nodes.get(depId);
360
+ return depNode?.status === ExecutionNodeStatus.COMPLETED;
361
+ }
362
+ );
363
+
364
+ if (allDepsCompleted) {
365
+ graph.readyQueue.push(dependentId);
366
+ }
367
+ }
368
+ }
369
+ }
370
+ });
371
+
372
+ executing.add(promise);
373
+ }
374
+
375
+ // Wait for at least one task to complete
376
+ if (executing.size > 0) {
377
+ await Promise.race(executing);
378
+ }
379
+ }
380
+
381
+ return results;
382
+ }
383
+
384
+ /**
385
+ * Find an executor for a task
386
+ */
387
+ private findExecutor(task: Task): TaskExecutor | undefined {
388
+ for (const executor of this.executors.values()) {
389
+ if (executor.canExecute(task)) {
390
+ return executor;
391
+ }
392
+ }
393
+ return undefined;
394
+ }
395
+
396
+ /**
397
+ * Collect inputs from completed dependencies
398
+ */
399
+ private collectInputs(
400
+ task: Task,
401
+ results: Map<EntityId, TaskResult>
402
+ ): Map<EntityId, unknown> {
403
+ const inputs = new Map<EntityId, unknown>();
404
+
405
+ for (const depId of task.dependencies) {
406
+ const result = results.get(depId);
407
+ if (result?.output !== undefined) {
408
+ inputs.set(depId, result.output);
409
+ }
410
+ }
411
+
412
+ return inputs;
413
+ }
414
+
415
+ /**
416
+ * Update node status and execution progress
417
+ */
418
+ private updateNodeStatus(
419
+ graph: ExecutionGraph,
420
+ nodeId: EntityId,
421
+ status: ExecutionNodeStatus
422
+ ): void {
423
+ const node = graph.nodes.get(nodeId) as MutableExecutionNode | undefined;
424
+ if (!node) {
425
+ return;
426
+ }
427
+
428
+ node.status = status;
429
+
430
+ if (status === ExecutionNodeStatus.COMPLETED) {
431
+ (graph as MutableExecutionGraph).completedCount++;
432
+ } else if (status === ExecutionNodeStatus.FAILED) {
433
+ (graph as MutableExecutionGraph).failedCount++;
434
+ }
435
+
436
+ // Update execution status
437
+ for (const execStatus of this.executions.values()) {
438
+ if (execStatus.planId === graph.planId) {
439
+ (execStatus as MutableExecutionStatus).progress = this.calculateProgress(graph);
440
+ }
441
+ }
442
+ }
443
+
444
+ /**
445
+ * Calculate execution progress
446
+ */
447
+ private calculateProgress(graph: ExecutionGraph): ExecutionProgress {
448
+ const total = graph.totalCount;
449
+ const completed = graph.completedCount;
450
+ const failed = graph.failedCount;
451
+ const running = Array.from(graph.nodes.values()).filter(
452
+ n => n.status === ExecutionNodeStatus.RUNNING
453
+ ).length;
454
+ const pending = total - completed - failed - running;
455
+
456
+ return {
457
+ total,
458
+ completed,
459
+ failed,
460
+ pending,
461
+ running,
462
+ percentage: total > 0 ? Math.round(((completed + failed) / total) * 100) : 0,
463
+ };
464
+ }
465
+
466
+ /**
467
+ * Update execution state
468
+ */
469
+ private updateExecutionState(executionId: EntityId, state: ExecutionState): void {
470
+ const status = this.executions.get(executionId);
471
+ if (status) {
472
+ this.executions.set(executionId, { ...status, state });
473
+ }
474
+ }
475
+
476
+ /**
477
+ * Emit execution event
478
+ */
479
+ private emitEvent(
480
+ type: ExecutionEventType,
481
+ executionId: EntityId,
482
+ data: unknown
483
+ ): void {
484
+ const event: ExecutionEvent = {
485
+ type,
486
+ executionId,
487
+ timestamp: new Date(),
488
+ data,
489
+ };
490
+
491
+ this.emit(type, event);
492
+ }
493
+
494
+ /**
495
+ * Generate a unique ID
496
+ */
497
+ private generateId(): EntityId {
498
+ return `exec-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Mutable execution node for internal use
504
+ */
505
+ interface MutableExecutionNode extends ExecutionNode {
506
+ status: ExecutionNodeStatus;
507
+ }
508
+
509
+ /**
510
+ * Mutable execution graph for internal use
511
+ */
512
+ interface MutableExecutionGraph extends ExecutionGraph {
513
+ completedCount: number;
514
+ failedCount: number;
515
+ }
516
+
517
+ /**
518
+ * Mutable execution status for internal use
519
+ */
520
+ interface MutableExecutionStatus extends ExecutionStatus {
521
+ progress: ExecutionProgress;
522
+ }