@librechat/agents 3.1.90 → 3.1.92

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 (94) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +9 -5
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +48 -14
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/instrumentation.cjs +2 -7
  6. package/dist/cjs/instrumentation.cjs.map +1 -1
  7. package/dist/cjs/langfuse.cjs +285 -0
  8. package/dist/cjs/langfuse.cjs.map +1 -0
  9. package/dist/cjs/main.cjs +25 -0
  10. package/dist/cjs/main.cjs.map +1 -1
  11. package/dist/cjs/run.cjs +75 -44
  12. package/dist/cjs/run.cjs.map +1 -1
  13. package/dist/cjs/stream.cjs +10 -3
  14. package/dist/cjs/stream.cjs.map +1 -1
  15. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +380 -0
  16. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -0
  17. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +997 -0
  18. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -0
  19. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +575 -0
  20. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -0
  21. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +165 -0
  22. package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -0
  23. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +17 -5
  24. package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
  25. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +110 -6
  26. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  27. package/dist/cjs/utils/callbacks.cjs +27 -0
  28. package/dist/cjs/utils/callbacks.cjs.map +1 -0
  29. package/dist/esm/agents/AgentContext.mjs +9 -5
  30. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  31. package/dist/esm/graphs/Graph.mjs +48 -14
  32. package/dist/esm/graphs/Graph.mjs.map +1 -1
  33. package/dist/esm/instrumentation.mjs +2 -7
  34. package/dist/esm/instrumentation.mjs.map +1 -1
  35. package/dist/esm/langfuse.mjs +275 -0
  36. package/dist/esm/langfuse.mjs.map +1 -0
  37. package/dist/esm/main.mjs +5 -1
  38. package/dist/esm/main.mjs.map +1 -1
  39. package/dist/esm/run.mjs +75 -44
  40. package/dist/esm/run.mjs.map +1 -1
  41. package/dist/esm/stream.mjs +10 -3
  42. package/dist/esm/stream.mjs.map +1 -1
  43. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +378 -0
  44. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -0
  45. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +994 -0
  46. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -0
  47. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +566 -0
  48. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -0
  49. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +155 -0
  50. package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -0
  51. package/dist/esm/tools/local/LocalExecutionEngine.mjs +17 -6
  52. package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
  53. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +111 -7
  54. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  55. package/dist/esm/utils/callbacks.mjs +24 -0
  56. package/dist/esm/utils/callbacks.mjs.map +1 -0
  57. package/dist/types/agents/AgentContext.d.ts +4 -1
  58. package/dist/types/graphs/Graph.d.ts +6 -5
  59. package/dist/types/index.d.ts +1 -0
  60. package/dist/types/langfuse.d.ts +57 -0
  61. package/dist/types/tools/cloudflare/CloudflareBridgeRuntime.d.ts +23 -0
  62. package/dist/types/tools/cloudflare/CloudflareProgrammaticToolCalling.d.ts +4 -0
  63. package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +21 -0
  64. package/dist/types/tools/cloudflare/CloudflareSandboxTools.d.ts +22 -0
  65. package/dist/types/tools/cloudflare/index.d.ts +4 -0
  66. package/dist/types/tools/local/LocalExecutionEngine.d.ts +1 -0
  67. package/dist/types/types/graph.d.ts +8 -0
  68. package/dist/types/types/run.d.ts +2 -2
  69. package/dist/types/types/tools.d.ts +118 -2
  70. package/dist/types/utils/callbacks.d.ts +5 -0
  71. package/package.json +4 -4
  72. package/src/__tests__/stream.eagerEventExecution.test.ts +66 -0
  73. package/src/agents/AgentContext.ts +13 -3
  74. package/src/graphs/Graph.ts +57 -16
  75. package/src/index.ts +1 -0
  76. package/src/instrumentation.ts +2 -7
  77. package/src/langfuse.ts +441 -0
  78. package/src/run.ts +105 -59
  79. package/src/specs/langfuse-callbacks.test.ts +75 -0
  80. package/src/specs/langfuse-config.test.ts +114 -0
  81. package/src/specs/langfuse-metadata.test.ts +19 -1
  82. package/src/stream.ts +13 -3
  83. package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +537 -0
  84. package/src/tools/cloudflare/CloudflareBridgeRuntime.ts +480 -0
  85. package/src/tools/cloudflare/CloudflareProgrammaticToolCalling.ts +1162 -0
  86. package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +744 -0
  87. package/src/tools/cloudflare/CloudflareSandboxTools.ts +225 -0
  88. package/src/tools/cloudflare/index.ts +4 -0
  89. package/src/tools/local/LocalExecutionEngine.ts +20 -4
  90. package/src/tools/local/resolveLocalExecutionTools.ts +169 -7
  91. package/src/types/graph.ts +9 -0
  92. package/src/types/run.ts +2 -7
  93. package/src/types/tools.ts +141 -2
  94. package/src/utils/callbacks.ts +39 -0
@@ -467,10 +467,11 @@ export type ToolOutputReferencesConfig = {
467
467
  */
468
468
  maxTotalSize?: number;
469
469
  };
470
- export type ToolExecutionEngine = 'sandbox' | 'local';
470
+ export type ToolExecutionEngine = 'sandbox' | 'local' | 'cloudflare-sandbox';
471
471
  /**
472
472
  * Records pre-write file contents so callers can rewind edits/writes
473
- * made by the local engine. Implementations live in `src/tools/local`.
473
+ * made by local-compatible coding-tool engines. Implementations live
474
+ * in `src/tools/local`.
474
475
  */
475
476
  export interface LocalFileCheckpointer {
476
477
  /**
@@ -586,6 +587,12 @@ export type LocalExecConfig = {
586
587
  * overridden together for non-host engines.
587
588
  */
588
589
  fs?: import('@/tools/local/workspaceFS').WorkspaceFS;
590
+ /**
591
+ * Set by custom execution backends that already provide their own
592
+ * sandbox boundary. Suppresses the local host-sandbox warning while
593
+ * preserving the warning for plain host `child_process` execution.
594
+ */
595
+ sandboxed?: boolean;
589
596
  };
590
597
  export type LocalExecutionConfig = {
591
598
  /**
@@ -740,11 +747,120 @@ export type LocalExecutionConfig = {
740
747
  timeoutMs?: number;
741
748
  };
742
749
  };
750
+ export type CloudflareSandboxExecOptions = {
751
+ cwd?: string;
752
+ env?: Record<string, string | undefined>;
753
+ timeout?: number;
754
+ stream?: boolean;
755
+ onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;
756
+ signal?: AbortSignal;
757
+ };
758
+ export type CloudflareSandboxExecResult = {
759
+ success?: boolean;
760
+ exitCode: number;
761
+ stdout: string;
762
+ stderr: string;
763
+ command?: string;
764
+ duration?: number;
765
+ timestamp?: string;
766
+ };
767
+ export type CloudflareSandboxReadFileResult = string | Buffer | Uint8Array | {
768
+ content: string | Buffer | Uint8Array | ReadableStream<Uint8Array>;
769
+ size?: number;
770
+ mimeType?: string;
771
+ encoding?: 'utf-8' | 'utf8' | 'base64';
772
+ isBinary?: boolean;
773
+ };
774
+ export type CloudflareSandboxListFilesOptions = {
775
+ recursive?: boolean;
776
+ includeHidden?: boolean;
777
+ };
778
+ export type CloudflareSandboxFileInfo = {
779
+ name: string;
780
+ absolutePath?: string;
781
+ relativePath?: string;
782
+ type?: 'file' | 'directory' | 'symlink' | 'other';
783
+ size?: number;
784
+ modifiedAt?: string;
785
+ mode?: string;
786
+ };
787
+ export type CloudflareSandboxListFilesResult = CloudflareSandboxFileInfo[] | {
788
+ files: CloudflareSandboxFileInfo[];
789
+ count?: number;
790
+ path?: string;
791
+ success?: boolean;
792
+ };
793
+ export interface CloudflareSandboxRuntime {
794
+ exec(command: string, options?: CloudflareSandboxExecOptions): Promise<CloudflareSandboxExecResult>;
795
+ readFile(path: string, options?: {
796
+ encoding?: string;
797
+ }): Promise<CloudflareSandboxReadFileResult>;
798
+ writeFile(path: string, content: string | ReadableStream<Uint8Array>, options?: {
799
+ encoding?: string;
800
+ }): Promise<unknown>;
801
+ mkdir(path: string, options?: {
802
+ recursive?: boolean;
803
+ }): Promise<unknown>;
804
+ listFiles(path: string, options?: CloudflareSandboxListFilesOptions): Promise<CloudflareSandboxListFilesResult>;
805
+ deleteFile(path: string): Promise<unknown>;
806
+ }
807
+ export type CloudflareSandboxExecutionConfig = {
808
+ sandbox: CloudflareSandboxRuntime | (() => CloudflareSandboxRuntime | Promise<CloudflareSandboxRuntime>);
809
+ /** Working directory inside the sandbox. Defaults to `/workspace`. */
810
+ workspaceRoot?: string;
811
+ /** Extra environment variables merged into sandbox command executions. */
812
+ env?: Record<string, string | undefined>;
813
+ /** Default timeout for sandbox commands, in milliseconds. */
814
+ timeoutMs?: number;
815
+ /** Maximum stdout/stderr characters surfaced to the model. */
816
+ maxOutputChars?: number;
817
+ /**
818
+ * Add the built-in coding suite when `engine` is `cloudflare-sandbox`.
819
+ * Defaults to true, matching the local execution backend.
820
+ */
821
+ includeCodingTools?: boolean;
822
+ /**
823
+ * Optional exact coding-tool names to expose when `includeCodingTools`
824
+ * is on. Defaults to the full local-parity Cloudflare bundle. Use this
825
+ * to publish a bash-only sandbox surface, for example file/search tools
826
+ * plus `bash_tool` and `run_tools_with_bash`, without exposing
827
+ * `execute_code`.
828
+ */
829
+ codingToolNames?: readonly string[];
830
+ /** Optional shell executable for bash-style tools. Defaults to `bash`. */
831
+ shell?: string;
832
+ /**
833
+ * Optional project-level compile check configuration. Mirrors the local
834
+ * execution backend.
835
+ */
836
+ compileCheck?: LocalExecutionConfig['compileCheck'];
837
+ /** Optional read-only guard for mutating coding tools. */
838
+ readOnly?: boolean;
839
+ /** Permit dangerous commands that the validator otherwise blocks. */
840
+ allowDangerousCommands?: LocalExecutionConfig['allowDangerousCommands'];
841
+ /** Tree-sitter-bash AST validation pass for bash commands. */
842
+ bashAst?: LocalExecutionConfig['bashAst'];
843
+ /**
844
+ * Enable per-Run file checkpointing for `edit_file` / `write_file`
845
+ * against the Cloudflare Sandbox workspace.
846
+ */
847
+ fileCheckpointing?: LocalExecutionConfig['fileCheckpointing'];
848
+ /** Maximum bytes to read in `read_file` before returning a stub. */
849
+ maxReadBytes?: LocalExecutionConfig['maxReadBytes'];
850
+ /** Controls whether `read_file` returns binary files as attachments. */
851
+ attachReadAttachments?: LocalExecutionConfig['attachReadAttachments'];
852
+ /** Maximum pre-encoding byte size to embed inline. */
853
+ maxAttachmentBytes?: LocalExecutionConfig['maxAttachmentBytes'];
854
+ /** Run a fast per-file syntax check after successful edits/writes. */
855
+ postEditSyntaxCheck?: LocalExecutionConfig['postEditSyntaxCheck'];
856
+ };
743
857
  export type ToolExecutionConfig = {
744
858
  /** `sandbox` preserves the remote Code API behavior and is the default. */
745
859
  engine?: ToolExecutionEngine;
746
860
  /** Local process execution settings used when `engine` is `local`. */
747
861
  local?: LocalExecutionConfig;
862
+ /** Cloudflare Sandbox execution settings used when `engine` is `cloudflare-sandbox`. */
863
+ cloudflare?: CloudflareSandboxExecutionConfig;
748
864
  };
749
865
  export type ProgrammaticCache = {
750
866
  toolMap: ToolMap;
@@ -0,0 +1,5 @@
1
+ import type { BaseCallbackHandler, CallbackHandlerMethods } from '@langchain/core/callbacks/base';
2
+ import type { Callbacks } from '@langchain/core/callbacks/manager';
3
+ export type CallbackEntry = BaseCallbackHandler | CallbackHandlerMethods;
4
+ export declare function appendCallbacks(callbacks: Callbacks | undefined, additions: readonly CallbackEntry[]): Callbacks;
5
+ export declare function findCallback(callbacks: Callbacks | undefined, predicate: (callback: CallbackEntry) => boolean): CallbackEntry | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.1.90",
3
+ "version": "3.1.92",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -227,9 +227,9 @@
227
227
  "@langchain/openai": "1.4.5",
228
228
  "@langchain/textsplitters": "^1.0.1",
229
229
  "@langchain/xai": "^1.3.17",
230
- "@langfuse/langchain": "^4.3.0",
231
- "@langfuse/otel": "^4.3.0",
232
- "@langfuse/tracing": "^4.3.0",
230
+ "@langfuse/langchain": "^5.3.0",
231
+ "@langfuse/otel": "^5.3.0",
232
+ "@langfuse/tracing": "^5.3.0",
233
233
  "@opentelemetry/sdk-node": "^0.218.0",
234
234
  "@scarf/scarf": "^1.4.0",
235
235
  "@types/diff": "^7.0.2",
@@ -2847,6 +2847,72 @@ describe('ChatModelStreamHandler eager event tool execution', () => {
2847
2847
  expect(graph.eagerEventToolCallChunks.size).toBe(0);
2848
2848
  });
2849
2849
 
2850
+ it('does not prestart streamed Cloudflare sandbox direct coding tools', async () => {
2851
+ const graph = createGraph({
2852
+ toolExecution: {
2853
+ engine: 'cloudflare-sandbox',
2854
+ cloudflare: { sandbox: {} },
2855
+ } as StandardGraph['toolExecution'],
2856
+ getAgentContext: jest.fn(
2857
+ (): Partial<AgentContext> => ({
2858
+ provider: Providers.OPENAI,
2859
+ reasoningKey: 'reasoning_content',
2860
+ toolDefinitions: [{ name: Constants.BASH_TOOL }, { name: 'weather' }],
2861
+ graphTools: [],
2862
+ agentId: 'agent_1',
2863
+ })
2864
+ ) as unknown as StandardGraph['getAgentContext'],
2865
+ });
2866
+ const dispatchSpy = jest.spyOn(events, 'safeDispatchCustomEvent');
2867
+ const handler = new ChatModelStreamHandler();
2868
+ const metadata = { langgraph_node: 'agent' };
2869
+
2870
+ await handler.handle(
2871
+ GraphEvents.CHAT_MODEL_STREAM,
2872
+ {
2873
+ chunk: {
2874
+ content: '',
2875
+ tool_call_chunks: [
2876
+ {
2877
+ id: 'call_weather',
2878
+ name: 'weather',
2879
+ args: '{"city":"NYC"}',
2880
+ index: 0,
2881
+ },
2882
+ ],
2883
+ } as unknown as t.StreamChunk,
2884
+ },
2885
+ metadata,
2886
+ graph
2887
+ );
2888
+ await handler.handle(
2889
+ GraphEvents.CHAT_MODEL_STREAM,
2890
+ {
2891
+ chunk: {
2892
+ content: '',
2893
+ tool_call_chunks: [
2894
+ {
2895
+ id: 'call_bash',
2896
+ name: Constants.BASH_TOOL,
2897
+ args: '{"command":"echo ok"}',
2898
+ index: 1,
2899
+ },
2900
+ ],
2901
+ } as unknown as t.StreamChunk,
2902
+ },
2903
+ metadata,
2904
+ graph
2905
+ );
2906
+
2907
+ expect(dispatchSpy).not.toHaveBeenCalledWith(
2908
+ GraphEvents.ON_TOOL_EXECUTE,
2909
+ expect.anything(),
2910
+ expect.anything()
2911
+ );
2912
+ expect(graph.eagerEventToolExecutions.size).toBe(0);
2913
+ expect(graph.eagerEventToolCallChunks.size).toBe(0);
2914
+ });
2915
+
2850
2916
  it('prestarts streamed remote bash tools when the next Anthropic tool call begins', async () => {
2851
2917
  const graph = createGraph({
2852
2918
  getAgentContext: jest.fn(
@@ -53,6 +53,7 @@ export class AgentContext {
53
53
  name,
54
54
  provider,
55
55
  clientOptions,
56
+ langfuse,
56
57
  tools,
57
58
  toolMap,
58
59
  toolEnd,
@@ -80,6 +81,7 @@ export class AgentContext {
80
81
  name: name ?? agentId,
81
82
  provider,
82
83
  clientOptions,
84
+ langfuse,
83
85
  maxContextTokens,
84
86
  streamBuffer,
85
87
  tools,
@@ -149,6 +151,8 @@ export class AgentContext {
149
151
  provider: Providers;
150
152
  /** Client options for this agent */
151
153
  clientOptions?: t.ClientOptions;
154
+ /** Per-agent Langfuse tracing configuration. */
155
+ langfuse?: t.LangfuseConfig;
152
156
  /** Token count map indexed by message position */
153
157
  indexTokenCountMap: Record<string, number | undefined> = {};
154
158
  /** Canonical pre-run token map used to restore token accounting on reset */
@@ -309,6 +313,7 @@ export class AgentContext {
309
313
  name,
310
314
  provider,
311
315
  clientOptions,
316
+ langfuse,
312
317
  maxContextTokens,
313
318
  streamBuffer,
314
319
  tokenCounter,
@@ -332,6 +337,7 @@ export class AgentContext {
332
337
  name?: string;
333
338
  provider: Providers;
334
339
  clientOptions?: t.ClientOptions;
340
+ langfuse?: t.LangfuseConfig;
335
341
  maxContextTokens?: number;
336
342
  streamBuffer?: number;
337
343
  tokenCounter?: t.TokenCounter;
@@ -355,6 +361,7 @@ export class AgentContext {
355
361
  this.name = name;
356
362
  this.provider = provider;
357
363
  this.clientOptions = clientOptions;
364
+ this.langfuse = langfuse;
358
365
  this.maxContextTokens = maxContextTokens;
359
366
  this.streamBuffer = streamBuffer;
360
367
  this.tokenCounter = tokenCounter;
@@ -458,11 +465,14 @@ export class AgentContext {
458
465
  }
459
466
 
460
467
  private hasAvailableTool(name: string): boolean {
461
- if (this.toolDefinitions?.some((tool) => tool.name === name)) return true;
462
- if (this.tools?.some((tool) => 'name' in tool && tool.name === name)) {
468
+ if (this.toolDefinitions?.some((tool) => tool.name === name) === true)
469
+ return true;
470
+ if (
471
+ this.tools?.some((tool) => 'name' in tool && tool.name === name) === true
472
+ ) {
463
473
  return true;
464
474
  }
465
- if (this.toolMap?.has(name)) return true;
475
+ if (this.toolMap?.has(name) === true) return true;
466
476
  return this.toolRegistry?.has(name) === true;
467
477
  }
468
478
 
@@ -52,14 +52,21 @@ import { attemptInvoke, tryFallbackProviders } from '@/llm/invoke';
52
52
  import { shouldTriggerSummarization } from '@/summarization';
53
53
  import { createSummarizeNode } from '@/summarization/node';
54
54
  import { messagesStateReducer } from '@/messages/reducer';
55
+ import { appendCallbacks } from '@/utils/callbacks';
55
56
  import { createSchemaOnlyTools } from '@/tools/schema';
56
57
  import { AgentContext } from '@/agents/AgentContext';
57
58
  import { createFakeStreamingLLM } from '@/llm/fake';
58
59
  import { handleToolCalls } from '@/tools/handlers';
59
60
  import { resolveLocalToolsForBinding } from '@/tools/local';
60
61
  import { createLocalCodingToolBundle } from '@/tools/local/LocalCodingTools';
62
+ import { createCloudflareCodingToolBundle } from '@/tools/cloudflare';
61
63
  import { isThinkingEnabled } from '@/llm/request';
62
64
  import { initializeModel } from '@/llm/init';
65
+ import {
66
+ createLangfuseHandler,
67
+ disposeLangfuseHandler,
68
+ createLangfuseTraceMetadata,
69
+ } from '@/langfuse';
63
70
  import { HandlerRegistry } from '@/events';
64
71
  import { ChatOpenAI } from '@/llm/openai';
65
72
  import { partitionAndMarkOpenRouterToolCache } from '@/llm/openrouter/toolCache';
@@ -337,11 +344,12 @@ export abstract class Graph<
337
344
  /**
338
345
  * Single per-Run file checkpointer shared across every ToolNode the
339
346
  * graph compiles. Lazily constructed when
340
- * `toolExecution.local.fileCheckpointing === true` so multi-agent
341
- * graphs see ONE snapshot store, not one-per-agent. Returns
342
- * undefined when checkpointing is disabled or the local engine
343
- * isn't selected. Exposed via `Run.getFileCheckpointer()` /
344
- * `Run.rewindFiles()`.
347
+ * `toolExecution.local.fileCheckpointing === true` or
348
+ * `toolExecution.cloudflare.fileCheckpointing === true` so
349
+ * multi-agent graphs see ONE snapshot store, not one-per-agent.
350
+ * Returns undefined when checkpointing is disabled or a supported
351
+ * coding-tool engine isn't selected. Exposed via
352
+ * `Run.getFileCheckpointer()` / `Run.rewindFiles()`.
345
353
  */
346
354
  private _fileCheckpointer?: t.LocalFileCheckpointer;
347
355
  /**
@@ -364,20 +372,32 @@ export abstract class Graph<
364
372
  if (this._fileCheckpointer != null) {
365
373
  return this._fileCheckpointer;
366
374
  }
367
- if (
368
- this.toolExecution?.engine !== 'local' ||
369
- this.toolExecution.local?.fileCheckpointing !== true
370
- ) {
371
- return undefined;
372
- }
373
375
  // Eagerly create via the bundle factory so the construction path
374
376
  // matches the bundle-only callers (and future bundle-internal
375
377
  // cleanup hooks fire). The bundle factory itself accepts a pre-
376
378
  // supplied checkpointer when present, so re-injecting this one
377
379
  // into every ToolNode is idempotent.
378
- const bundle = createLocalCodingToolBundle(this.toolExecution.local ?? {});
379
- this._fileCheckpointer = bundle.checkpointer;
380
- return this._fileCheckpointer;
380
+ if (
381
+ this.toolExecution?.engine === 'local' &&
382
+ this.toolExecution.local?.fileCheckpointing === true
383
+ ) {
384
+ const bundle = createLocalCodingToolBundle(
385
+ this.toolExecution.local ?? {}
386
+ );
387
+ this._fileCheckpointer = bundle.checkpointer;
388
+ return this._fileCheckpointer;
389
+ }
390
+ if (
391
+ this.toolExecution?.engine === 'cloudflare-sandbox' &&
392
+ this.toolExecution.cloudflare?.fileCheckpointing === true
393
+ ) {
394
+ const bundle = createCloudflareCodingToolBundle(
395
+ this.toolExecution.cloudflare
396
+ );
397
+ this._fileCheckpointer = bundle.checkpointer;
398
+ return this._fileCheckpointer;
399
+ }
400
+ return undefined;
381
401
  }
382
402
  }
383
403
 
@@ -1318,6 +1338,25 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1318
1338
  { force: true }
1319
1339
  );
1320
1340
 
1341
+ const langfuseHandler = createLangfuseHandler({
1342
+ langfuse: agentContext.langfuse,
1343
+ userId: config.configurable?.user_id as string | undefined,
1344
+ sessionId: config.configurable?.thread_id as string | undefined,
1345
+ traceMetadata: createLangfuseTraceMetadata({
1346
+ messageId: this.runId,
1347
+ parentMessageId: config.configurable?.requestBody?.parentMessageId,
1348
+ agentId,
1349
+ agentName: agentContext.name,
1350
+ }),
1351
+ tags: ['librechat', 'agent'],
1352
+ });
1353
+ const invokeConfig = langfuseHandler
1354
+ ? {
1355
+ ...config,
1356
+ callbacks: appendCallbacks(config.callbacks, [langfuseHandler]),
1357
+ }
1358
+ : config;
1359
+
1321
1360
  try {
1322
1361
  result = await attemptInvoke(
1323
1362
  {
@@ -1326,17 +1365,19 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1326
1365
  provider: agentContext.provider,
1327
1366
  context: this,
1328
1367
  },
1329
- config
1368
+ invokeConfig
1330
1369
  );
1331
1370
  } catch (primaryError) {
1332
1371
  result = await tryFallbackProviders({
1333
1372
  fallbacks,
1334
1373
  tools: agentContext.tools,
1335
1374
  messages: finalMessages,
1336
- config,
1375
+ config: invokeConfig,
1337
1376
  primaryError,
1338
1377
  context: this,
1339
1378
  });
1379
+ } finally {
1380
+ await disposeLangfuseHandler(langfuseHandler);
1340
1381
  }
1341
1382
 
1342
1383
  if (!result) {
package/src/index.ts CHANGED
@@ -27,6 +27,7 @@ export * from './tools/ToolNode';
27
27
  export * from './tools/schema';
28
28
  export * from './tools/handlers';
29
29
  export * from './tools/local';
30
+ export * from './tools/cloudflare';
30
31
  export * from './tools/search';
31
32
 
32
33
  /* Misc. */
@@ -5,14 +5,9 @@ import { isPresent } from '@/utils/misc';
5
5
  if (
6
6
  isPresent(process.env.LANGFUSE_SECRET_KEY) &&
7
7
  isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&
8
- isPresent(process.env.LANGFUSE_BASE_URL)
8
+ isPresent(process.env.LANGFUSE_BASE_URL ?? process.env.LANGFUSE_BASEURL)
9
9
  ) {
10
- const langfuseSpanProcessor = new LangfuseSpanProcessor({
11
- publicKey: process.env.LANGFUSE_PUBLIC_KEY,
12
- secretKey: process.env.LANGFUSE_SECRET_KEY,
13
- baseUrl: process.env.LANGFUSE_BASE_URL,
14
- environment: process.env.LANGFUSE_TRACING_ENVIRONMENT ?? process.env.NODE_ENV ?? 'development',
15
- });
10
+ const langfuseSpanProcessor = new LangfuseSpanProcessor();
16
11
 
17
12
  const sdk = new NodeSDK({
18
13
  spanProcessors: [langfuseSpanProcessor],