illuma-agents 1.0.23 → 1.0.24

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/src/run.ts CHANGED
@@ -4,8 +4,6 @@ import { CallbackHandler } from '@langfuse/langchain';
4
4
  import { PromptTemplate } from '@langchain/core/prompts';
5
5
  import { RunnableLambda } from '@langchain/core/runnables';
6
6
  import { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';
7
- import { MemorySaver } from '@langchain/langgraph-checkpoint';
8
- import { Command } from '@langchain/langgraph';
9
7
  import type {
10
8
  MessageContentComplex,
11
9
  BaseMessage,
@@ -24,7 +22,6 @@ import { StandardGraph } from '@/graphs/Graph';
24
22
  import { HandlerRegistry } from '@/events';
25
23
  import { isOpenAILike } from '@/utils/llm';
26
24
  import { isPresent } from '@/utils/misc';
27
- import type { BrowserInterrupt, BrowserActionResult } from '@/tools/BrowserInterruptTools';
28
25
 
29
26
  export const defaultOmitOptions = new Set([
30
27
  'stream',
@@ -39,35 +36,11 @@ export const defaultOmitOptions = new Set([
39
36
  'additionalModelRequestFields',
40
37
  ]);
41
38
 
42
- /** Global checkpointer store for browser mode (keyed by runId) */
43
- const browserCheckpointers = new Map<string, MemorySaver>();
44
-
45
- /**
46
- * Get or create a checkpointer for browser mode
47
- */
48
- export function getBrowserCheckpointer(runId: string): MemorySaver {
49
- let checkpointer = browserCheckpointers.get(runId);
50
- if (!checkpointer) {
51
- checkpointer = new MemorySaver();
52
- browserCheckpointers.set(runId, checkpointer);
53
- }
54
- return checkpointer;
55
- }
56
-
57
- /**
58
- * Clean up a browser checkpointer when done
59
- */
60
- export function cleanupBrowserCheckpointer(runId: string): void {
61
- browserCheckpointers.delete(runId);
62
- }
63
-
64
39
  export class Run<_T extends t.BaseGraphState> {
65
40
  id: string;
66
41
  private tokenCounter?: t.TokenCounter;
67
42
  private handlerRegistry?: HandlerRegistry;
68
43
  private indexTokenCountMap?: Record<string, number>;
69
- /** Whether this run is in browser extension mode */
70
- browserMode: boolean = false;
71
44
  graphRunnable?: t.CompiledStateWorkflow;
72
45
  Graph: StandardGraph | MultiAgentGraph | undefined;
73
46
  returnContent: boolean = false;
@@ -81,7 +54,6 @@ export class Run<_T extends t.BaseGraphState> {
81
54
  this.id = runId;
82
55
  this.tokenCounter = config.tokenCounter;
83
56
  this.indexTokenCountMap = config.indexTokenCountMap;
84
- this.browserMode = config.browserMode ?? false;
85
57
 
86
58
  const handlerRegistry = new HandlerRegistry();
87
59
 
@@ -101,24 +73,16 @@ export class Run<_T extends t.BaseGraphState> {
101
73
 
102
74
  /** Handle different graph types */
103
75
  if (config.graphConfig.type === 'multi-agent') {
104
- // For multi-agent, browser mode checkpointer support not yet implemented
105
76
  this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);
106
77
  if (this.Graph) {
107
78
  this.Graph.handlerRegistry = handlerRegistry;
108
79
  }
109
80
  } else {
110
81
  /** Default to legacy graph for 'standard' or undefined type */
111
- // In browser mode, inject checkpointer into compileOptions BEFORE creating the graph
112
- const graphConfig = { ...config.graphConfig };
113
- if (this.browserMode) {
114
- const checkpointer = getBrowserCheckpointer(runId);
115
- graphConfig.compileOptions = {
116
- ...graphConfig.compileOptions,
117
- checkpointer,
118
- };
119
- }
120
- this.graphRunnable = this.createLegacyGraph(graphConfig);
82
+ this.graphRunnable = this.createLegacyGraph(config.graphConfig);
121
83
  if (this.Graph) {
84
+ this.Graph.compileOptions =
85
+ config.graphConfig.compileOptions ?? this.Graph.compileOptions;
122
86
  this.Graph.handlerRegistry = handlerRegistry;
123
87
  }
124
88
  }
@@ -489,225 +453,4 @@ export class Run<_T extends t.BaseGraphState> {
489
453
  );
490
454
  }
491
455
  }
492
-
493
- /**
494
- * Process stream with browser interrupt support.
495
- * Uses streamEvents() like processStream to emit SSE events,
496
- * then checks for interrupts after stream completes.
497
- */
498
- async *processBrowserStream(
499
- inputs: t.IState,
500
- config: Partial<RunnableConfig> & { version: 'v1' | 'v2'; run_id?: string },
501
- streamOptions?: t.EventStreamOptions
502
- ): AsyncGenerator<
503
- | { type: 'event'; data: unknown }
504
- | { type: 'interrupt'; data: BrowserInterrupt }
505
- | { type: 'done'; data?: MessageContentComplex[] }
506
- > {
507
- if (this.graphRunnable == null) {
508
- throw new Error(
509
- 'Run not initialized. Make sure to use Run.create() to instantiate the Run.'
510
- );
511
- }
512
- if (!this.Graph) {
513
- throw new Error(
514
- 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'
515
- );
516
- }
517
-
518
- this.Graph.resetValues(streamOptions?.keepContent);
519
-
520
- if (!this.id) {
521
- throw new Error('Run ID not provided');
522
- }
523
-
524
- config.run_id = this.id;
525
- // Set up thread_id for checkpointing (required for interrupt/resume)
526
- config.configurable = Object.assign(config.configurable ?? {}, {
527
- run_id: this.id,
528
- thread_id: this.id, // Use run ID as thread ID for browser sessions
529
- });
530
-
531
- // Set up callbacks for SSE event emission (same as processStream)
532
- const customEventCallback = this.createCustomEventCallback();
533
-
534
- const baseCallbacks = (config.callbacks as t.ProvidedCallbacks) ?? [];
535
- const streamCallbacks = streamOptions?.callbacks
536
- ? this.getCallbacks(streamOptions.callbacks)
537
- : [];
538
-
539
- config.callbacks = baseCallbacks.concat(streamCallbacks).concat({
540
- [Callback.CUSTOM_EVENT]: customEventCallback,
541
- });
542
-
543
- // Use streamEvents like processStream to emit proper SSE events
544
- const stream = this.graphRunnable.streamEvents(inputs, config, {
545
- raiseError: true,
546
- ignoreCustomEvent: true,
547
- });
548
-
549
- let wasInterrupted = false;
550
-
551
- try {
552
- for await (const event of stream) {
553
- const { data, metadata, ...info } = event;
554
- const eventName: t.EventName = info.event;
555
-
556
- // Skip custom events as they're handled by our callback
557
- if (eventName === GraphEvents.ON_CUSTOM_EVENT) {
558
- continue;
559
- }
560
-
561
- const handler = this.handlerRegistry?.getHandler(eventName);
562
- if (handler) {
563
- await handler.handle(eventName, data, metadata, this.Graph);
564
- }
565
-
566
- // Also yield the event for the caller to process
567
- yield { type: 'event', data: event };
568
- }
569
- } catch (error) {
570
- // streamEvents may throw when interrupt happens
571
- // Check if this is an interrupt-related termination
572
- const errorMessage = error instanceof Error ? error.message : String(error);
573
- if (errorMessage.includes('interrupt') || errorMessage.includes('GraphInterrupt')) {
574
- wasInterrupted = true;
575
- } else {
576
- throw error;
577
- }
578
- }
579
-
580
- // After stream completes, check for pending interrupts using getState
581
- // The checkpointer stores the interrupt state
582
- try {
583
- const state = await this.graphRunnable.getState(config);
584
- if (state?.tasks) {
585
- for (const task of state.tasks) {
586
- if (task.interrupts && task.interrupts.length > 0) {
587
- for (const interruptInfo of task.interrupts) {
588
- if (interruptInfo.value?.type === 'browser_interrupt') {
589
- yield { type: 'interrupt', data: interruptInfo.value as BrowserInterrupt };
590
- return; // Stop after yielding interrupt
591
- }
592
- }
593
- }
594
- }
595
- }
596
- } catch (stateError) {
597
- // getState may fail if no checkpointer - that's ok for non-browser flows
598
- console.debug('[processBrowserStream] Could not get state:', stateError);
599
- }
600
-
601
- // Stream completed without interrupt
602
- if (this.returnContent) {
603
- yield { type: 'done', data: this.Graph.getContentParts() };
604
- } else {
605
- yield { type: 'done' };
606
- }
607
- }
608
-
609
- /**
610
- * Resume a browser stream after interrupt.
611
- * Call this with the result from the browser extension.
612
- * Uses streamEvents() to emit proper SSE events during resume.
613
- */
614
- async *resumeBrowserStream(
615
- result: BrowserActionResult,
616
- config: Partial<RunnableConfig> & { version: 'v1' | 'v2'; run_id?: string },
617
- streamOptions?: t.EventStreamOptions
618
- ): AsyncGenerator<
619
- | { type: 'event'; data: unknown }
620
- | { type: 'interrupt'; data: BrowserInterrupt }
621
- | { type: 'done'; data?: MessageContentComplex[] }
622
- > {
623
- if (this.graphRunnable == null) {
624
- throw new Error(
625
- 'Run not initialized. Make sure to use Run.create() to instantiate the Run.'
626
- );
627
- }
628
- if (!this.Graph) {
629
- throw new Error(
630
- 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'
631
- );
632
- }
633
-
634
- if (!this.id) {
635
- throw new Error('Run ID not provided');
636
- }
637
-
638
- config.run_id = this.id;
639
- config.configurable = Object.assign(config.configurable ?? {}, {
640
- run_id: this.id,
641
- thread_id: this.id,
642
- });
643
-
644
- // Set up callbacks for SSE event emission (same as processStream)
645
- const customEventCallback = this.createCustomEventCallback();
646
-
647
- const baseCallbacks = (config.callbacks as t.ProvidedCallbacks) ?? [];
648
- const streamCallbacks = streamOptions?.callbacks
649
- ? this.getCallbacks(streamOptions.callbacks)
650
- : [];
651
-
652
- config.callbacks = baseCallbacks.concat(streamCallbacks).concat({
653
- [Callback.CUSTOM_EVENT]: customEventCallback,
654
- });
655
-
656
- // Use Command to resume with the browser result
657
- const resumeCommand = new Command({ resume: result });
658
-
659
- // Use streamEvents for proper SSE event emission
660
- const stream = this.graphRunnable.streamEvents(resumeCommand, config, {
661
- raiseError: true,
662
- ignoreCustomEvent: true,
663
- });
664
-
665
- try {
666
- for await (const event of stream) {
667
- const { data, metadata, ...info } = event;
668
- const eventName: t.EventName = info.event;
669
-
670
- if (eventName === GraphEvents.ON_CUSTOM_EVENT) {
671
- continue;
672
- }
673
-
674
- const handler = this.handlerRegistry?.getHandler(eventName);
675
- if (handler) {
676
- await handler.handle(eventName, data, metadata, this.Graph);
677
- }
678
-
679
- yield { type: 'event', data: event };
680
- }
681
- } catch (error) {
682
- const errorMessage = error instanceof Error ? error.message : String(error);
683
- if (!errorMessage.includes('interrupt') && !errorMessage.includes('GraphInterrupt')) {
684
- throw error;
685
- }
686
- }
687
-
688
- // Check for additional interrupts after resume
689
- try {
690
- const state = await this.graphRunnable.getState(config);
691
- if (state?.tasks) {
692
- for (const task of state.tasks) {
693
- if (task.interrupts && task.interrupts.length > 0) {
694
- for (const interruptInfo of task.interrupts) {
695
- if (interruptInfo.value?.type === 'browser_interrupt') {
696
- yield { type: 'interrupt', data: interruptInfo.value as BrowserInterrupt };
697
- return;
698
- }
699
- }
700
- }
701
- }
702
- }
703
- } catch (stateError) {
704
- console.debug('[resumeBrowserStream] Could not get state:', stateError);
705
- }
706
-
707
- if (this.returnContent) {
708
- yield { type: 'done', data: this.Graph.getContentParts() };
709
- } else {
710
- yield { type: 'done' };
711
- }
712
- }
713
456
  }
package/src/types/run.ts CHANGED
@@ -115,14 +115,6 @@ export type RunConfig = {
115
115
  returnContent?: boolean;
116
116
  tokenCounter?: TokenCounter;
117
117
  indexTokenCountMap?: Record<string, number>;
118
- /**
119
- * Enable browser extension mode with interrupt-based tool execution.
120
- * When true:
121
- * - Uses MemorySaver checkpointer for pause/resume
122
- * - Browser tools will interrupt execution and wait for extension results
123
- * - Extension must call resume endpoint with Command to continue
124
- */
125
- browserMode?: boolean;
126
118
  };
127
119
 
128
120
  export type ProvidedCallbacks =