@illuma-ai/agents 1.1.18 → 1.1.20

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 (56) hide show
  1. package/dist/cjs/common/enum.cjs +2 -0
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +133 -6
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  5. package/dist/cjs/main.cjs +3 -0
  6. package/dist/cjs/main.cjs.map +1 -1
  7. package/dist/cjs/nodes/ApprovalGateNode.cjs +75 -0
  8. package/dist/cjs/nodes/ApprovalGateNode.cjs.map +1 -0
  9. package/dist/cjs/run.cjs +47 -1
  10. package/dist/cjs/run.cjs.map +1 -1
  11. package/dist/cjs/tools/ToolNode.cjs +21 -18
  12. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  13. package/dist/cjs/types/graph.cjs.map +1 -1
  14. package/dist/cjs/utils/run.cjs +6 -1
  15. package/dist/cjs/utils/run.cjs.map +1 -1
  16. package/dist/esm/common/enum.mjs +2 -0
  17. package/dist/esm/common/enum.mjs.map +1 -1
  18. package/dist/esm/graphs/MultiAgentGraph.mjs +133 -6
  19. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  20. package/dist/esm/main.mjs +1 -0
  21. package/dist/esm/main.mjs.map +1 -1
  22. package/dist/esm/nodes/ApprovalGateNode.mjs +72 -0
  23. package/dist/esm/nodes/ApprovalGateNode.mjs.map +1 -0
  24. package/dist/esm/run.mjs +47 -1
  25. package/dist/esm/run.mjs.map +1 -1
  26. package/dist/esm/tools/ToolNode.mjs +22 -19
  27. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  28. package/dist/esm/types/graph.mjs.map +1 -1
  29. package/dist/esm/utils/run.mjs +6 -1
  30. package/dist/esm/utils/run.mjs.map +1 -1
  31. package/dist/types/common/enum.d.ts +2 -0
  32. package/dist/types/graphs/MultiAgentGraph.d.ts +6 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/nodes/ApprovalGateNode.d.ts +49 -0
  35. package/dist/types/nodes/index.d.ts +2 -0
  36. package/dist/types/run.d.ts +25 -1
  37. package/dist/types/tools/ToolNode.d.ts +7 -5
  38. package/dist/types/types/graph.d.ts +40 -0
  39. package/dist/types/types/run.d.ts +6 -0
  40. package/dist/types/types/tools.d.ts +7 -9
  41. package/package.json +1 -1
  42. package/src/common/enum.ts +2 -0
  43. package/src/graphs/MultiAgentGraph.ts +166 -6
  44. package/src/index.ts +3 -0
  45. package/src/nodes/ApprovalGateNode.ts +117 -0
  46. package/src/nodes/__tests__/ApprovalGateNode.test.ts +206 -0
  47. package/src/nodes/index.ts +5 -0
  48. package/src/run.ts +57 -2
  49. package/src/specs/agent-handoffs-bedrock.integration.test.ts +2 -2
  50. package/src/specs/agent-handoffs.test.ts +153 -6
  51. package/src/tools/ToolNode.ts +28 -23
  52. package/src/tools/__tests__/ToolApproval.test.ts +162 -325
  53. package/src/types/graph.ts +41 -0
  54. package/src/types/run.ts +6 -0
  55. package/src/types/tools.ts +7 -9
  56. package/src/utils/run.ts +9 -1
@@ -342,6 +342,32 @@ export type StandardGraphInput = {
342
342
  indexTokenCountMap?: Record<string, number>;
343
343
  };
344
344
 
345
+ /**
346
+ * Configuration for an approval gate placed on a sequence edge.
347
+ * When present, the graph inserts an approval gate node between the source
348
+ * and destination agents. The gate ALWAYS fires (regardless of ExecutionContext)
349
+ * and calls interrupt() to pause the graph for human approval.
350
+ */
351
+ export type ApprovalGateConfig = {
352
+ /** Unique identifier for this gate (used as node ID suffix) */
353
+ gateId: string;
354
+ /**
355
+ * Approval channel — where the approval UI is rendered.
356
+ * - 'chat': SSE-based chat UI (default)
357
+ * - 'outlook': MS Graph Actionable Messages
358
+ * - 'telegram': Telegram Bot inline keyboard
359
+ */
360
+ channel?: 'chat' | 'outlook' | 'telegram';
361
+ /** Optional human-readable prompt shown to the approver */
362
+ prompt?: string;
363
+ /** Optional approver identifier (e.g., email, user ID) */
364
+ approver?: string;
365
+ /** Timeout in ms before the gate auto-expires (default: 5 minutes) */
366
+ timeoutMs?: number;
367
+ /** What to do on denial: 'stop' ends the graph, 'skip' skips the destination agent */
368
+ onDeny?: 'stop' | 'skip';
369
+ };
370
+
345
371
  export type GraphEdge = {
346
372
  /** Agent ID, use a list for multiple sources */
347
373
  from: string | string[];
@@ -389,10 +415,25 @@ export type GraphEdge = {
389
415
  * Defaults to DEFAULT_HANDOFF_MAX_RESULT_CHARS (32768 chars, ~8192 tokens).
390
416
  */
391
417
  maxResultChars?: number;
418
+ /**
419
+ * Approval gate configuration for sequence edges.
420
+ * When set, inserts an approval gate node between source and destination.
421
+ * The gate ALWAYS fires regardless of ExecutionContext (unlike tool approval).
422
+ */
423
+ approvalGate?: ApprovalGateConfig;
392
424
  };
393
425
 
394
426
  export type MultiAgentGraphInput = StandardGraphInput & {
395
427
  edges: GraphEdge[];
428
+ /**
429
+ * When set, the graph routes START to this agent instead of the default starting nodes.
430
+ * Used for multi-turn resumption: the caller reads `lastActiveAgentId` from the
431
+ * previous turn's metadata and passes it here so follow-up messages route to the
432
+ * agent that last handled the conversation.
433
+ *
434
+ * If the agent ID is invalid (not in the graph), falls back to default starting nodes.
435
+ */
436
+ resumeFromAgentId?: string;
396
437
  };
397
438
 
398
439
  /**
package/src/types/run.ts CHANGED
@@ -101,6 +101,12 @@ export type MultiAgentGraphConfig = {
101
101
  compileOptions?: g.CompileOptions;
102
102
  agents: g.AgentInputs[];
103
103
  edges: g.GraphEdge[];
104
+ /**
105
+ * Resume from a specific agent on the next turn.
106
+ * When set, START routes directly to this agent instead of default starting nodes.
107
+ * @see MultiAgentGraphInput.resumeFromAgentId
108
+ */
109
+ resumeFromAgentId?: string;
104
110
  };
105
111
 
106
112
  export type StandardGraphConfig = Omit<
@@ -316,16 +316,14 @@ export type ToolApprovalResponse = {
316
316
  };
317
317
 
318
318
  /**
319
- * Event payload dispatched via ON_TOOL_APPROVAL_REQUIRED.
320
- * Extends ToolApprovalRequest with promise resolve/reject for async flow.
321
- * The host handles the event by showing UI and calling resolve/reject.
319
+ * Notification payload dispatched via ON_TOOL_APPROVAL_REQUIRED.
320
+ * Data-only no resolve/reject callbacks. The approval mechanism is handled
321
+ * by LangGraph's native interrupt()/Command({ resume }) pattern.
322
+ *
323
+ * The host persists this data (e.g., in MongoDB) and sends UI events.
324
+ * The actual approval response comes back via Command({ resume: ToolApprovalResponse }).
322
325
  */
323
- export type ToolApprovalEvent = ToolApprovalRequest & {
324
- /** Promise resolver - host calls this with the approval response */
325
- resolve: (response: ToolApprovalResponse) => void;
326
- /** Promise rejector - host calls this on fatal error */
327
- reject: (error: Error) => void;
328
- };
326
+ export type ToolApprovalNotification = ToolApprovalRequest;
329
327
 
330
328
  /** Search mode: code_interpreter uses external sandbox, local uses safe substring matching */
331
329
  export type ToolSearchMode = 'code_interpreter' | 'local';
package/src/utils/run.ts CHANGED
@@ -96,7 +96,15 @@ export class RunnableCallable<I = unknown, O = unknown> extends Runnable<I, O> {
96
96
  mergeConfigs(this.config, options)
97
97
  );
98
98
  } else {
99
- returnValue = await this.func(input, mergeConfigs(this.config, options));
99
+ const mergedConfig = mergeConfigs(this.config, options);
100
+ // Set up AsyncLocalStorage context so LangGraph's interrupt() can find
101
+ // the graph config via getRunnableConfig(). Without this, interrupt()
102
+ // throws "Called interrupt() outside the context of a graph" because
103
+ // RunnableCallable (unlike RunnableLambda) doesn't use _callWithConfig.
104
+ returnValue = await AsyncLocalStorageProviderSingleton.runWithConfig(
105
+ mergedConfig,
106
+ () => this.func(input, mergedConfig)
107
+ );
100
108
  }
101
109
 
102
110
  if (Runnable.isRunnable(returnValue) && this.recurse) {