copilotkit-agent-runner 0.1.6

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.
@@ -0,0 +1,632 @@
1
+ import * as _ag_ui_client from '@ag-ui/client';
2
+ import { BaseEvent } from '@ag-ui/core';
3
+ import { AgentRunnerRunRequest, AgentRunner, AgentRunnerStopRequest, AgentRunnerConnectRequest } from '@copilotkitnext/runtime';
4
+ import { Observable } from 'rxjs';
5
+ import { LangGraphAgent } from '@copilotkit/runtime/langgraph';
6
+
7
+ /**
8
+ * Configuration for the HistoryHydratingAgentRunner.
9
+ */
10
+ interface HistoryHydratingRunnerConfig {
11
+ /**
12
+ * The LangGraphAgent instance to delegate run() calls to.
13
+ */
14
+ agent: LangGraphAgent;
15
+ /**
16
+ * LangGraph deployment URL (required).
17
+ * Used to create fresh Client instances for history fetching.
18
+ */
19
+ deploymentUrl: string;
20
+ /**
21
+ * Graph ID for the agent.
22
+ */
23
+ graphId: string;
24
+ /**
25
+ * LangSmith API key for authentication (optional).
26
+ */
27
+ langsmithApiKey?: string;
28
+ /**
29
+ * Maximum number of history checkpoints to fetch.
30
+ * Default: 100, Maximum: 1000 (LangGraph API limit)
31
+ */
32
+ historyLimit?: number;
33
+ /**
34
+ * Client timeout in milliseconds.
35
+ * Default: 1800000 (30 minutes) - supports long-running agents.
36
+ */
37
+ clientTimeoutMs?: number;
38
+ /**
39
+ * Enable debug logging.
40
+ * Default: false
41
+ */
42
+ debug?: boolean;
43
+ /**
44
+ * Optional function to extract additional state from the request.
45
+ * Called during run() to enrich the state passed to the agent.
46
+ *
47
+ * @param input - The run request input
48
+ * @param forwardedProps - Optional forwarded props from CopilotKit
49
+ * @returns State object to merge with existing state
50
+ */
51
+ stateExtractor?: StateExtractor;
52
+ }
53
+ /**
54
+ * Function type for extracting state from run requests.
55
+ */
56
+ type StateExtractor = (input: AgentRunnerRunRequest["input"], forwardedProps?: Record<string, unknown>) => Record<string, unknown>;
57
+ /**
58
+ * LangGraph message format from thread state.
59
+ */
60
+ interface LangGraphMessage {
61
+ id: string;
62
+ type: "human" | "ai" | "tool" | "system";
63
+ content: string | Array<{
64
+ type: string;
65
+ text?: string;
66
+ }>;
67
+ tool_calls?: Array<{
68
+ id: string;
69
+ name: string;
70
+ args: Record<string, unknown>;
71
+ }>;
72
+ tool_call_id?: string;
73
+ }
74
+ /**
75
+ * Thread state from LangGraph checkpoint.
76
+ */
77
+ interface ThreadState {
78
+ values: {
79
+ messages?: LangGraphMessage[];
80
+ [key: string]: unknown;
81
+ };
82
+ next: string[];
83
+ config?: unknown;
84
+ created_at?: string;
85
+ parent_config?: unknown;
86
+ tasks?: Array<{
87
+ id: string;
88
+ name: string;
89
+ interrupts?: Array<{
90
+ value?: unknown;
91
+ [key: string]: unknown;
92
+ }>;
93
+ [key: string]: unknown;
94
+ }>;
95
+ checkpoint: unknown;
96
+ metadata: unknown;
97
+ parent_checkpoint?: unknown;
98
+ }
99
+ /**
100
+ * Tool used to predict state (for intermediate state emission).
101
+ */
102
+ interface PredictStateTool {
103
+ tool: string;
104
+ state_key: string;
105
+ tool_argument: string;
106
+ }
107
+ /**
108
+ * Frozen agent config to prevent shared state contamination.
109
+ */
110
+ interface FrozenAgentConfig {
111
+ deploymentUrl: string;
112
+ graphId: string;
113
+ langsmithApiKey?: string;
114
+ clientTimeoutMs: number;
115
+ }
116
+
117
+ /**
118
+ * Custom AgentRunner that extends CopilotKit's base runner to add
119
+ * message history hydration support for LangGraph threads.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * import { HistoryHydratingAgentRunner, createIsolatedAgent } from 'copilotkit-agent-runner';
124
+ *
125
+ * const agent = createIsolatedAgent({
126
+ * deploymentUrl: process.env.LANGGRAPH_DEPLOYMENT_URL!,
127
+ * graphId: "my-agent",
128
+ * langsmithApiKey: process.env.LANGSMITH_API_KEY,
129
+ * });
130
+ *
131
+ * const runner = new HistoryHydratingAgentRunner({
132
+ * agent,
133
+ * deploymentUrl: process.env.LANGGRAPH_DEPLOYMENT_URL!,
134
+ * graphId: "my-agent",
135
+ * langsmithApiKey: process.env.LANGSMITH_API_KEY,
136
+ * historyLimit: 100,
137
+ * });
138
+ *
139
+ * const runtime = new CopilotRuntime({
140
+ * agents: { "my-agent": agent },
141
+ * runner,
142
+ * });
143
+ * ```
144
+ */
145
+ declare class HistoryHydratingAgentRunner extends AgentRunner {
146
+ private agent;
147
+ private historyLimit;
148
+ private debug;
149
+ private stateExtractor?;
150
+ private activeRun;
151
+ /**
152
+ * Frozen agent config to prevent shared state contamination.
153
+ * We store the raw config values and create fresh Agent/Client instances per request.
154
+ * This is critical because Vercel serverless can bundle multiple routes together,
155
+ * causing module-level state to leak between different agent configurations.
156
+ */
157
+ private readonly frozenConfig;
158
+ constructor(config: HistoryHydratingRunnerConfig);
159
+ /**
160
+ * Creates a fresh LangGraphAgent instance using the frozen config.
161
+ * Uses our isolated agent creator to prevent shared state contamination.
162
+ */
163
+ private createFreshAgent;
164
+ /**
165
+ * Creates a fresh LangGraph Client instance using the frozen config.
166
+ * This prevents shared state contamination in serverless environments.
167
+ */
168
+ private createFreshClient;
169
+ /**
170
+ * Log a message if debug mode is enabled.
171
+ */
172
+ private log;
173
+ /**
174
+ * Log a warning.
175
+ */
176
+ private warn;
177
+ /**
178
+ * Log an error.
179
+ */
180
+ private error;
181
+ /**
182
+ * Run the agent with a FRESH agent instance.
183
+ * CRITICAL: We cannot trust request.agent (cloned by CopilotKit) because
184
+ * its internal Client may have been corrupted by shared module state in
185
+ * Vercel serverless environments. Create a completely fresh agent with
186
+ * our frozen config to guarantee the correct deployment URL is used.
187
+ */
188
+ run(request: AgentRunnerRunRequest): Observable<{
189
+ type: _ag_ui_client.EventType.TEXT_MESSAGE_START;
190
+ role: "developer" | "system" | "assistant" | "user";
191
+ messageId: string;
192
+ timestamp?: number | undefined;
193
+ rawEvent?: any;
194
+ } | {
195
+ type: _ag_ui_client.EventType.TEXT_MESSAGE_CONTENT;
196
+ messageId: string;
197
+ delta: string;
198
+ timestamp?: number | undefined;
199
+ rawEvent?: any;
200
+ } | {
201
+ type: _ag_ui_client.EventType.TEXT_MESSAGE_END;
202
+ messageId: string;
203
+ timestamp?: number | undefined;
204
+ rawEvent?: any;
205
+ } | {
206
+ type: _ag_ui_client.EventType.TOOL_CALL_START;
207
+ toolCallId: string;
208
+ toolCallName: string;
209
+ timestamp?: number | undefined;
210
+ rawEvent?: any;
211
+ parentMessageId?: string | undefined;
212
+ } | {
213
+ type: _ag_ui_client.EventType.TOOL_CALL_ARGS;
214
+ toolCallId: string;
215
+ delta: string;
216
+ timestamp?: number | undefined;
217
+ rawEvent?: any;
218
+ } | {
219
+ type: _ag_ui_client.EventType.TOOL_CALL_END;
220
+ toolCallId: string;
221
+ timestamp?: number | undefined;
222
+ rawEvent?: any;
223
+ } | {
224
+ type: _ag_ui_client.EventType.THINKING_TEXT_MESSAGE_START;
225
+ timestamp?: number | undefined;
226
+ rawEvent?: any;
227
+ } | {
228
+ type: _ag_ui_client.EventType.THINKING_TEXT_MESSAGE_CONTENT;
229
+ delta: string;
230
+ timestamp?: number | undefined;
231
+ rawEvent?: any;
232
+ } | {
233
+ type: _ag_ui_client.EventType.THINKING_TEXT_MESSAGE_END;
234
+ timestamp?: number | undefined;
235
+ rawEvent?: any;
236
+ } | {
237
+ type: _ag_ui_client.EventType.TOOL_CALL_RESULT;
238
+ content: string;
239
+ toolCallId: string;
240
+ messageId: string;
241
+ role?: "tool" | undefined;
242
+ timestamp?: number | undefined;
243
+ rawEvent?: any;
244
+ } | {
245
+ type: _ag_ui_client.EventType.THINKING_START;
246
+ timestamp?: number | undefined;
247
+ rawEvent?: any;
248
+ title?: string | undefined;
249
+ } | {
250
+ type: _ag_ui_client.EventType.THINKING_END;
251
+ timestamp?: number | undefined;
252
+ rawEvent?: any;
253
+ } | {
254
+ type: _ag_ui_client.EventType.STATE_SNAPSHOT;
255
+ timestamp?: number | undefined;
256
+ rawEvent?: any;
257
+ snapshot?: any;
258
+ } | {
259
+ type: _ag_ui_client.EventType.STATE_DELTA;
260
+ delta: any[];
261
+ timestamp?: number | undefined;
262
+ rawEvent?: any;
263
+ } | {
264
+ type: _ag_ui_client.EventType.MESSAGES_SNAPSHOT;
265
+ messages: ({
266
+ id: string;
267
+ role: "developer";
268
+ content: string;
269
+ name?: string | undefined;
270
+ } | {
271
+ id: string;
272
+ role: "system";
273
+ content: string;
274
+ name?: string | undefined;
275
+ } | {
276
+ id: string;
277
+ role: "assistant";
278
+ name?: string | undefined;
279
+ content?: string | undefined;
280
+ toolCalls?: {
281
+ function: {
282
+ name: string;
283
+ arguments: string;
284
+ };
285
+ type: "function";
286
+ id: string;
287
+ }[] | undefined;
288
+ } | {
289
+ id: string;
290
+ role: "user";
291
+ content: string | ({
292
+ type: "text";
293
+ text: string;
294
+ } | {
295
+ type: "binary";
296
+ mimeType: string;
297
+ id?: string | undefined;
298
+ url?: string | undefined;
299
+ data?: string | undefined;
300
+ filename?: string | undefined;
301
+ })[];
302
+ name?: string | undefined;
303
+ } | {
304
+ id: string;
305
+ role: "tool";
306
+ content: string;
307
+ toolCallId: string;
308
+ error?: string | undefined;
309
+ } | {
310
+ id: string;
311
+ role: "activity";
312
+ content: Record<string, any>;
313
+ activityType: string;
314
+ })[];
315
+ timestamp?: number | undefined;
316
+ rawEvent?: any;
317
+ } | {
318
+ type: _ag_ui_client.EventType.RAW;
319
+ timestamp?: number | undefined;
320
+ rawEvent?: any;
321
+ event?: any;
322
+ source?: string | undefined;
323
+ } | {
324
+ name: string;
325
+ type: _ag_ui_client.EventType.CUSTOM;
326
+ value?: any;
327
+ timestamp?: number | undefined;
328
+ rawEvent?: any;
329
+ } | {
330
+ type: _ag_ui_client.EventType.RUN_STARTED;
331
+ threadId: string;
332
+ runId: string;
333
+ parentRunId?: string | undefined;
334
+ timestamp?: number | undefined;
335
+ rawEvent?: any;
336
+ input?: {
337
+ threadId: string;
338
+ runId: string;
339
+ messages: ({
340
+ id: string;
341
+ role: "developer";
342
+ content: string;
343
+ name?: string | undefined;
344
+ } | {
345
+ id: string;
346
+ role: "system";
347
+ content: string;
348
+ name?: string | undefined;
349
+ } | {
350
+ id: string;
351
+ role: "assistant";
352
+ name?: string | undefined;
353
+ content?: string | undefined;
354
+ toolCalls?: {
355
+ function: {
356
+ name: string;
357
+ arguments: string;
358
+ };
359
+ type: "function";
360
+ id: string;
361
+ }[] | undefined;
362
+ } | {
363
+ id: string;
364
+ role: "user";
365
+ content: string | ({
366
+ type: "text";
367
+ text: string;
368
+ } | {
369
+ type: "binary";
370
+ mimeType: string;
371
+ id?: string | undefined;
372
+ url?: string | undefined;
373
+ data?: string | undefined;
374
+ filename?: string | undefined;
375
+ })[];
376
+ name?: string | undefined;
377
+ } | {
378
+ id: string;
379
+ role: "tool";
380
+ content: string;
381
+ toolCallId: string;
382
+ error?: string | undefined;
383
+ } | {
384
+ id: string;
385
+ role: "activity";
386
+ content: Record<string, any>;
387
+ activityType: string;
388
+ })[];
389
+ tools: {
390
+ name: string;
391
+ description: string;
392
+ parameters?: any;
393
+ }[];
394
+ context: {
395
+ value: string;
396
+ description: string;
397
+ }[];
398
+ parentRunId?: string | undefined;
399
+ state?: any;
400
+ forwardedProps?: any;
401
+ } | undefined;
402
+ } | {
403
+ type: _ag_ui_client.EventType.RUN_FINISHED;
404
+ threadId: string;
405
+ runId: string;
406
+ timestamp?: number | undefined;
407
+ rawEvent?: any;
408
+ result?: any;
409
+ } | {
410
+ message: string;
411
+ type: _ag_ui_client.EventType.RUN_ERROR;
412
+ code?: string | undefined;
413
+ timestamp?: number | undefined;
414
+ rawEvent?: any;
415
+ } | {
416
+ type: _ag_ui_client.EventType.STEP_STARTED;
417
+ stepName: string;
418
+ timestamp?: number | undefined;
419
+ rawEvent?: any;
420
+ } | {
421
+ type: _ag_ui_client.EventType.STEP_FINISHED;
422
+ stepName: string;
423
+ timestamp?: number | undefined;
424
+ rawEvent?: any;
425
+ } | {
426
+ type: _ag_ui_client.EventType;
427
+ name: string;
428
+ value: any;
429
+ }>;
430
+ /**
431
+ * Delegate isRunning to the agent.
432
+ */
433
+ isRunning(): Promise<boolean>;
434
+ /**
435
+ * Delegate stop to the agent.
436
+ */
437
+ stop(_request: AgentRunnerStopRequest): Promise<boolean | undefined>;
438
+ /**
439
+ * Override connect to add history hydration support.
440
+ *
441
+ * When reconnecting to a thread:
442
+ * 1. Fetches ALL thread history (checkpoints) from LangGraph
443
+ * 2. Extracts and deduplicates messages from all checkpoints
444
+ * 3. Transforms historical messages to CopilotKit format
445
+ * 4. Emits MESSAGES_SNAPSHOT and STATE_SNAPSHOT events
446
+ * 5. Completes the observable
447
+ */
448
+ connect(request: AgentRunnerConnectRequest): Observable<BaseEvent>;
449
+ /**
450
+ * Joins an active stream and processes its events.
451
+ *
452
+ * This method connects to an already-running LangGraph execution and
453
+ * processes all incoming events, transforming them to BaseEvent format.
454
+ *
455
+ * Tracks started messages and tool calls to handle mid-stream joins where
456
+ * we might receive CONTENT/END events without having seen START events.
457
+ */
458
+ private joinAndProcessStream;
459
+ }
460
+
461
+ /**
462
+ * LangGraph Agent Isolation Utilities
463
+ *
464
+ * Fixes shared state contamination in Vercel serverless (Fluid Compute)
465
+ * where CopilotKit's LangGraphAgent can get wrong deploymentUrl due to
466
+ * module-level state being shared between bundled routes.
467
+ *
468
+ * Root cause: CopilotKit's clone() passes config by reference, not by value.
469
+ * Our fix: Create completely isolated agents with verified URLs.
470
+ */
471
+
472
+ /**
473
+ * Configuration for creating an isolated LangGraph agent.
474
+ */
475
+ interface CreateIsolatedAgentConfig {
476
+ /**
477
+ * LangGraph deployment URL.
478
+ */
479
+ deploymentUrl: string;
480
+ /**
481
+ * Graph ID for the agent.
482
+ */
483
+ graphId: string;
484
+ /**
485
+ * LangSmith API key for authentication (optional).
486
+ */
487
+ langsmithApiKey?: string;
488
+ /**
489
+ * Client timeout in milliseconds.
490
+ * Default: 1800000 (30 minutes)
491
+ */
492
+ clientTimeoutMs?: number;
493
+ /**
494
+ * Enable debug mode on the agent.
495
+ */
496
+ debug?: boolean;
497
+ }
498
+ /**
499
+ * Creates a completely isolated LangGraphAgent that cannot be contaminated
500
+ * by shared module state. This is the "nuclear option" fix for serverless
501
+ * environments like Vercel Fluid Compute.
502
+ *
503
+ * Key features:
504
+ * 1. Creates agent with fresh, frozen config
505
+ * 2. Verifies the internal client has correct URL
506
+ * 3. Force-replaces client if contamination detected
507
+ *
508
+ * @example
509
+ * ```typescript
510
+ * const agent = createIsolatedAgent({
511
+ * deploymentUrl: process.env.LANGGRAPH_DEPLOYMENT_URL!,
512
+ * graphId: "my-agent",
513
+ * langsmithApiKey: process.env.LANGSMITH_API_KEY,
514
+ * });
515
+ * ```
516
+ */
517
+ declare function createIsolatedAgent(config: CreateIsolatedAgentConfig): LangGraphAgent;
518
+
519
+ /**
520
+ * Default timeout for LangGraph Client HTTP requests (30 minutes).
521
+ * Long timeout supports long-running agent workflows.
522
+ */
523
+ declare const DEFAULT_TIMEOUT: number;
524
+ /**
525
+ * Default number of history checkpoints to fetch.
526
+ */
527
+ declare const DEFAULT_HISTORY_LIMIT = 100;
528
+ /**
529
+ * Maximum history limit allowed by the LangGraph API.
530
+ */
531
+ declare const MAX_HISTORY_LIMIT = 1000;
532
+
533
+ /**
534
+ * Custom event names that CopilotKit uses for manual emissions.
535
+ * These match exactly what CopilotKit's LangGraphAgent expects.
536
+ */
537
+ declare enum CustomEventNames {
538
+ CopilotKitManuallyEmitMessage = "copilotkit_manually_emit_message",
539
+ CopilotKitManuallyEmitToolCall = "copilotkit_manually_emit_tool_call",
540
+ CopilotKitManuallyEmitIntermediateState = "copilotkit_manually_emit_intermediate_state",
541
+ CopilotKitExit = "copilotkit_exit",
542
+ /** Emitted when an MCP tool result is streamed (e.g. Google Drive MCP). */
543
+ MCPToolResult = "mcp_tool_result",
544
+ /** Emitted when MCP tool execution starts (for streaming progress). */
545
+ MCPToolStart = "mcp_tool_start"
546
+ }
547
+
548
+ /**
549
+ * LangGraph event types for stream processing.
550
+ * These correspond to LangChain/LangGraph lifecycle events.
551
+ */
552
+ declare enum LangGraphEventTypes {
553
+ OnChatModelStart = "on_chat_model_start",
554
+ OnChatModelStream = "on_chat_model_stream",
555
+ OnChatModelEnd = "on_chat_model_end",
556
+ OnToolStart = "on_tool_start",
557
+ OnToolEnd = "on_tool_end",
558
+ OnChainStart = "on_chain_start",
559
+ OnChainEnd = "on_chain_end"
560
+ }
561
+
562
+ /**
563
+ * Transformed message in CopilotKit format.
564
+ */
565
+ interface TransformedMessage {
566
+ id: string;
567
+ role: "user" | "assistant" | "system" | "tool";
568
+ content: string;
569
+ toolCalls?: Array<{
570
+ id: string;
571
+ type: "function";
572
+ function: {
573
+ name: string;
574
+ arguments: string;
575
+ };
576
+ }>;
577
+ toolCallId?: string;
578
+ }
579
+ /**
580
+ * Extracts text content from LangGraph message content.
581
+ * Handles both string and array formats.
582
+ */
583
+ declare function extractContent(content: string | Array<{
584
+ type: string;
585
+ text?: string;
586
+ }>): string;
587
+ /**
588
+ * Transforms LangGraph messages to CopilotKit message format.
589
+ *
590
+ * Based on the `ut` function from @ag-ui/langgraph but adapted
591
+ * for standalone use.
592
+ */
593
+ declare function transformMessages(messages: LangGraphMessage[], options?: {
594
+ debug?: boolean;
595
+ }): TransformedMessage[];
596
+
597
+ /**
598
+ * Context for stream processing.
599
+ */
600
+ interface StreamProcessorContext {
601
+ threadId: string;
602
+ runId: string;
603
+ subscriber: {
604
+ next: (event: BaseEvent) => void;
605
+ };
606
+ startedMessages?: Set<string>;
607
+ startedToolCalls?: Set<string>;
608
+ debug?: boolean;
609
+ manuallyEmittedState?: Record<string, unknown>;
610
+ }
611
+ /**
612
+ * Stream chunk from LangGraph.
613
+ */
614
+ interface StreamChunk {
615
+ id?: string;
616
+ event: string;
617
+ data: unknown;
618
+ metadata?: Record<string, unknown>;
619
+ }
620
+ /**
621
+ * Processes a single stream chunk and transforms it to BaseEvent format.
622
+ *
623
+ * Based on CopilotKit's event processing patterns from the agent's .run method.
624
+ * Handles all event types including custom events, metadata filtering, and
625
+ * transformations for TEXT_MESSAGE and TOOL_CALL events.
626
+ */
627
+ declare function processStreamChunk(chunk: StreamChunk, context: StreamProcessorContext): Promise<{
628
+ runId: string;
629
+ manuallyEmittedState?: Record<string, unknown>;
630
+ }>;
631
+
632
+ export { type CreateIsolatedAgentConfig, CustomEventNames, DEFAULT_HISTORY_LIMIT, DEFAULT_TIMEOUT, type FrozenAgentConfig, HistoryHydratingAgentRunner, type HistoryHydratingRunnerConfig, LangGraphEventTypes, type LangGraphMessage, MAX_HISTORY_LIMIT, type PredictStateTool, type StateExtractor, type StreamChunk, type StreamProcessorContext, type ThreadState, type TransformedMessage, createIsolatedAgent, extractContent, processStreamChunk, transformMessages };