@librechat/agents 2.0.5 → 2.1.1

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 (87) hide show
  1. package/dist/cjs/common/enum.cjs +1 -0
  2. package/dist/cjs/common/enum.cjs.map +1 -1
  3. package/dist/cjs/events.cjs +10 -0
  4. package/dist/cjs/events.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +34 -5
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/llm/anthropic/llm.cjs +1 -3
  8. package/dist/cjs/llm/anthropic/llm.cjs.map +1 -1
  9. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  10. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  11. package/dist/cjs/llm/fake.cjs +55 -0
  12. package/dist/cjs/llm/fake.cjs.map +1 -0
  13. package/dist/cjs/llm/providers.cjs +7 -5
  14. package/dist/cjs/llm/providers.cjs.map +1 -1
  15. package/dist/cjs/llm/text.cjs.map +1 -1
  16. package/dist/cjs/messages.cjs.map +1 -1
  17. package/dist/cjs/run.cjs +3 -7
  18. package/dist/cjs/run.cjs.map +1 -1
  19. package/dist/cjs/splitStream.cjs.map +1 -1
  20. package/dist/cjs/stream.cjs +93 -55
  21. package/dist/cjs/stream.cjs.map +1 -1
  22. package/dist/cjs/tools/CodeExecutor.cjs +8 -2
  23. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  24. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  25. package/dist/cjs/utils/graph.cjs.map +1 -1
  26. package/dist/cjs/utils/llm.cjs.map +1 -1
  27. package/dist/cjs/utils/misc.cjs.map +1 -1
  28. package/dist/cjs/utils/run.cjs.map +1 -1
  29. package/dist/cjs/utils/title.cjs.map +1 -1
  30. package/dist/esm/common/enum.mjs +1 -0
  31. package/dist/esm/common/enum.mjs.map +1 -1
  32. package/dist/esm/events.mjs +10 -0
  33. package/dist/esm/events.mjs.map +1 -1
  34. package/dist/esm/graphs/Graph.mjs +35 -6
  35. package/dist/esm/graphs/Graph.mjs.map +1 -1
  36. package/dist/esm/llm/anthropic/llm.mjs +1 -3
  37. package/dist/esm/llm/anthropic/llm.mjs.map +1 -1
  38. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  39. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  40. package/dist/esm/llm/fake.mjs +52 -0
  41. package/dist/esm/llm/fake.mjs.map +1 -0
  42. package/dist/esm/llm/providers.mjs +8 -6
  43. package/dist/esm/llm/providers.mjs.map +1 -1
  44. package/dist/esm/llm/text.mjs.map +1 -1
  45. package/dist/esm/messages.mjs.map +1 -1
  46. package/dist/esm/run.mjs +3 -7
  47. package/dist/esm/run.mjs.map +1 -1
  48. package/dist/esm/splitStream.mjs.map +1 -1
  49. package/dist/esm/stream.mjs +94 -56
  50. package/dist/esm/stream.mjs.map +1 -1
  51. package/dist/esm/tools/CodeExecutor.mjs +9 -3
  52. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  53. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  54. package/dist/esm/utils/graph.mjs.map +1 -1
  55. package/dist/esm/utils/llm.mjs.map +1 -1
  56. package/dist/esm/utils/misc.mjs.map +1 -1
  57. package/dist/esm/utils/run.mjs.map +1 -1
  58. package/dist/esm/utils/title.mjs.map +1 -1
  59. package/dist/types/common/enum.d.ts +2 -1
  60. package/dist/types/events.d.ts +4 -1
  61. package/dist/types/graphs/Graph.d.ts +9 -13
  62. package/dist/types/llm/fake.d.ts +21 -0
  63. package/dist/types/specs/spec.utils.d.ts +1 -0
  64. package/dist/types/stream.d.ts +9 -13
  65. package/dist/types/types/graph.d.ts +16 -0
  66. package/dist/types/types/llm.d.ts +10 -5
  67. package/dist/types/types/run.d.ts +4 -12
  68. package/dist/types/types/stream.d.ts +12 -0
  69. package/package.json +15 -26
  70. package/src/common/enum.ts +1 -0
  71. package/src/events.ts +13 -1
  72. package/src/graphs/Graph.ts +43 -21
  73. package/src/llm/fake.ts +83 -0
  74. package/src/llm/providers.ts +7 -5
  75. package/src/run.ts +3 -7
  76. package/src/scripts/simple.ts +28 -14
  77. package/src/specs/anthropic.simple.test.ts +204 -0
  78. package/src/specs/openai.simple.test.ts +204 -0
  79. package/src/specs/reasoning.test.ts +165 -0
  80. package/src/specs/spec.utils.ts +3 -0
  81. package/src/stream.ts +100 -72
  82. package/src/tools/CodeExecutor.ts +8 -2
  83. package/src/types/graph.ts +18 -1
  84. package/src/types/llm.ts +10 -5
  85. package/src/types/run.ts +5 -13
  86. package/src/types/stream.ts +14 -1
  87. package/src/utils/llmConfig.ts +7 -1
@@ -2,6 +2,7 @@ import type OpenAITypes from 'openai';
2
2
  import type { MessageContentImageUrl, MessageContentText, ToolMessage, BaseMessage } from '@langchain/core/messages';
3
3
  import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
4
4
  import type { LLMResult, Generation } from '@langchain/core/outputs';
5
+ import type { ToolEndEvent } from '@/types/tools';
5
6
  import { StepTypes, ContentTypes, GraphEvents } from '@/common/enum';
6
7
  export type HandleLLMEnd = (output: LLMResult, runId: string, parentRunId?: string, tags?: string[]) => void;
7
8
  export type MetadataAggregatorResult = {
@@ -206,3 +207,14 @@ export type SplitStreamHandlers = Partial<{
206
207
  data: ReasoningDeltaEvent;
207
208
  }) => void;
208
209
  }>;
210
+ export type ContentAggregator = ({ event, data }: {
211
+ event: GraphEvents;
212
+ data: RunStep | MessageDeltaEvent | RunStepDeltaEvent | {
213
+ result: ToolEndEvent;
214
+ };
215
+ }) => void;
216
+ export type ContentAggregatorResult = {
217
+ stepMap: Map<string, RunStep | undefined>;
218
+ contentParts: Array<MessageContentComplex | undefined>;
219
+ aggregateContent: ContentAggregator;
220
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "2.0.5",
3
+ "version": "2.1.1",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -45,9 +45,9 @@
45
45
  "code_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec.ts --provider 'google' --name 'Jo' --location 'New York, NY'",
46
46
  "image": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/image.ts --provider 'vertexai' --name 'Jo' --location 'New York, NY'",
47
47
  "code_exec_simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_simple.ts --provider 'vertexai' --name 'Jo' --location 'New York, NY'",
48
- "simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/simple.ts --provider 'vertexai' --name 'Jo' --location 'New York, NY'",
48
+ "simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/simple.ts --provider 'deepseek' --name 'Jo' --location 'New York, NY'",
49
49
  "memory": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/memory.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
50
- "tool-test": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
50
+ "tool-test": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'alibaba' --name 'Jo' --location 'New York, NY'",
51
51
  "abort": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/abort.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
52
52
  "start:cli2": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/cli2.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
53
53
  "script2": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/proto/example_test.ts",
@@ -74,6 +74,7 @@
74
74
  "@langchain/aws": "^0.1.3",
75
75
  "@langchain/community": "^0.3.27",
76
76
  "@langchain/core": "^0.3.37",
77
+ "@langchain/deepseek": "^0.0.1",
77
78
  "@langchain/google-genai": "^0.1.7",
78
79
  "@langchain/google-vertexai": "^0.1.8",
79
80
  "@langchain/langgraph": "^0.2.41",
@@ -84,7 +85,8 @@
84
85
  "@smithy/protocol-http": "^3.0.6",
85
86
  "@smithy/signature-v4": "^2.0.10",
86
87
  "@smithy/util-utf8": "^2.0.0",
87
- "dotenv": "^16.4.5",
88
+ "dotenv": "^16.4.7",
89
+ "https-proxy-agent": "^7.0.6",
88
90
  "nanoid": "^3.3.7"
89
91
  },
90
92
  "resolutions": {
@@ -103,38 +105,25 @@
103
105
  "@rollup/plugin-json": "^6.1.0",
104
106
  "@rollup/plugin-node-resolve": "^15.2.3",
105
107
  "@rollup/plugin-terser": "^0.4.4",
106
- "@rollup/plugin-typescript": "^11.1.6",
108
+ "@rollup/plugin-typescript": "^12.1.2",
107
109
  "@swc/core": "^1.6.13",
108
- "@types/babel__generator": "^7.6.8",
109
- "@types/babel__template": "^7.4.4",
110
- "@types/istanbul-lib-report": "^3.0.3",
111
110
  "@types/jest": "^29.5.14",
112
111
  "@types/node": "^20.14.11",
113
- "@types/rollup": "^0.54.0",
114
112
  "@types/yargs-parser": "^21.0.3",
115
- "@typescript-eslint/eslint-plugin": "^7.16.1",
116
- "@typescript-eslint/parser": "^7.16.1",
117
- "better-sqlite3": "^9.6.0",
118
- "concurrently": "^8.2.2",
119
- "cross-env": "^7.0.3",
120
- "eslint": "^8.57.0",
121
- "eslint-import-resolver-typescript": "^3.6.1",
122
- "eslint-plugin-import": "^2.29.1",
123
- "husky": "^9.0.11",
124
- "javascript-obfuscator": "^4.1.1",
113
+ "@typescript-eslint/eslint-plugin": "^8.24.0",
114
+ "@typescript-eslint/parser": "^8.24.0",
115
+ "eslint": "^9.20.1",
116
+ "eslint-import-resolver-typescript": "^3.7.0",
117
+ "eslint-plugin-import": "^2.31.0",
118
+ "husky": "^9.1.7",
125
119
  "jest": "^29.7.0",
126
120
  "lint-staged": "^15.2.7",
127
- "nodemon": "^3.1.4",
128
- "prettier": "^3.3.2",
129
- "rimraf": "^6.0.0",
130
- "rollup": "^4.18.1",
121
+ "prettier": "^3.5.1",
122
+ "rollup": "^4.34.6",
131
123
  "rollup-plugin-cleandir": "^2.0.0",
132
- "rollup-plugin-cleaner": "^1.0.0",
133
124
  "rollup-plugin-obfuscator": "^1.1.0",
134
- "rollup-plugin-visualizer": "^5.12.0",
135
125
  "ts-jest": "^29.2.5",
136
126
  "ts-node": "^10.9.2",
137
- "ts-node-dev": "^2.0.0",
138
127
  "tsc-alias": "^1.8.10",
139
128
  "tsconfig-paths": "^4.2.0",
140
129
  "tslib": "^2.6.3",
@@ -78,6 +78,7 @@ export enum Providers {
78
78
  OLLAMA = 'ollama',
79
79
  GOOGLE = 'google',
80
80
  AZURE = 'azureOpenAI',
81
+ DEEPSEEK = 'deepseek',
81
82
  }
82
83
 
83
84
  export enum GraphNodeKeys {
package/src/events.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable no-console */
2
2
  // src/events.ts
3
+ import type { UsageMetadata, BaseMessageFields } from '@langchain/core/messages';
3
4
  import type { Graph } from '@/graphs';
4
5
  import type * as t from '@/types';
5
6
  import { handleToolCalls } from '@/stream';
@@ -18,6 +19,14 @@ export class HandlerRegistry {
18
19
  }
19
20
 
20
21
  export class ModelEndHandler implements t.EventHandler {
22
+ collectedUsage?: UsageMetadata[];
23
+ constructor(collectedUsage?: UsageMetadata[]) {
24
+ if (collectedUsage && !Array.isArray(collectedUsage)) {
25
+ throw new Error('collectedUsage must be an array');
26
+ }
27
+ this.collectedUsage = collectedUsage;
28
+ }
29
+
21
30
  handle(event: string, data: t.ModelEndData, metadata?: Record<string, unknown>, graph?: Graph): void {
22
31
  if (!graph || !metadata) {
23
32
  console.warn(`Graph or metadata not found in ${event} event`);
@@ -25,6 +34,9 @@ export class ModelEndHandler implements t.EventHandler {
25
34
  }
26
35
 
27
36
  const usage = data?.output?.usage_metadata;
37
+ if (usage != null && this.collectedUsage != null) {
38
+ this.collectedUsage.push(usage);
39
+ }
28
40
 
29
41
  console.log(`====== ${event.toUpperCase()} ======`);
30
42
  console.dir({
@@ -117,7 +129,7 @@ export class LLMStreamHandler implements t.EventHandler {
117
129
  }
118
130
  }
119
131
 
120
- export const createMetadataAggregator = (_collected?: Record<string, unknown>[]): t.MetadataAggregatorResult => {
132
+ export const createMetadataAggregator = (_collected?: Record<string, NonNullable<BaseMessageFields['response_metadata']>>[]): t.MetadataAggregatorResult => {
121
133
  const collected = _collected || [];
122
134
 
123
135
  const handleLLMEnd: t.HandleLLMEnd = (output) => {
@@ -10,7 +10,7 @@ import { dispatchCustomEvent } from '@langchain/core/callbacks/dispatch';
10
10
  import { AIMessageChunk, ToolMessage, SystemMessage } from '@langchain/core/messages';
11
11
  import type { BaseMessage } from '@langchain/core/messages';
12
12
  import type * as t from '@/types';
13
- import { Providers, GraphEvents, GraphNodeKeys, StepTypes, Callback } from '@/common';
13
+ import { Providers, GraphEvents, GraphNodeKeys, StepTypes, Callback, ContentTypes } from '@/common';
14
14
  import { getChatModelClass, manualToolStreamProviders } from '@/llm/providers';
15
15
  import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
16
16
  import {
@@ -20,6 +20,7 @@ import {
20
20
  formatAnthropicArtifactContent,
21
21
  } from '@/messages';
22
22
  import { resetIfNotEmpty, isOpenAILike, isGoogleLike, joinKeys, sleep } from '@/utils';
23
+ import { createFakeStreamingLLM } from '@/llm/fake';
23
24
  import { HandlerRegistry } from '@/events';
24
25
 
25
26
  const { AGENT, TOOLS } = GraphNodeKeys;
@@ -56,10 +57,15 @@ export abstract class Graph<
56
57
  abstract dispatchRunStep(stepKey: string, stepDetails: t.StepDetails): string;
57
58
  abstract dispatchRunStepDelta(id: string, delta: t.ToolCallDelta): void;
58
59
  abstract dispatchMessageDelta(id: string, delta: t.MessageDelta): void;
60
+ abstract dispatchReasoningDelta(stepId: string, delta: t.ReasoningDelta): void;
59
61
  abstract handleToolCallCompleted(data: t.ToolEndData, metadata?: Record<string, unknown>): void;
60
62
 
61
63
  abstract createCallModel(): (state: T, config?: RunnableConfig) => Promise<Partial<T>>;
62
64
  abstract createWorkflow(): t.CompiledWorkflow<T>;
65
+ lastToken?: string;
66
+ tokenTypeSwitch?: 'reasoning' | 'content';
67
+ reasoningKey: 'reasoning_content' | 'reasoning' = 'reasoning_content';
68
+ currentTokenType: ContentTypes.TEXT | ContentTypes.THINK = ContentTypes.TEXT;
63
69
  messageStepHasToolCalls: Map<string, boolean> = new Map();
64
70
  messageIdsByStepKey: Map<string, string> = new Map();
65
71
  prelimMessageIdsByStepKey: Map<string, string> = new Map();
@@ -96,37 +102,30 @@ export class StandardGraph extends Graph<
96
102
  constructor({
97
103
  runId,
98
104
  tools,
105
+ signal,
99
106
  toolMap,
100
107
  provider,
101
- clientOptions,
102
- instructions,
103
- signal,
104
- additional_instructions = '',
105
108
  streamBuffer,
109
+ instructions,
110
+ reasoningKey,
111
+ clientOptions,
106
112
  toolEnd = false,
107
- } : {
108
- runId?: string;
109
- signal?: AbortSignal;
110
- provider: Providers;
111
- tools?: t.GenericTool[];
112
- toolMap?: t.ToolMap;
113
- clientOptions: Record<string, unknown>;
114
- instructions?: string;
115
- additional_instructions?: string;
116
- streamBuffer?: number;
117
- toolEnd?: boolean;
118
- }) {
113
+ additional_instructions = '',
114
+ } : t.StandardGraphInput) {
119
115
  super();
120
116
  this.runId = runId;
121
117
  this.tools = tools;
118
+ this.signal = signal;
119
+ this.toolEnd = toolEnd;
122
120
  this.toolMap = toolMap;
123
121
  this.provider = provider;
124
- this.signal = signal;
125
- this.clientOptions = clientOptions;
126
122
  this.streamBuffer = streamBuffer;
123
+ this.clientOptions = clientOptions;
127
124
  this.graphState = this.createGraphState();
128
125
  this.boundModel = this.initializeModel();
129
- this.toolEnd = toolEnd;
126
+ if (reasoningKey) {
127
+ this.reasoningKey = reasoningKey;
128
+ }
130
129
 
131
130
  let finalInstructions = instructions ?? '';
132
131
  if (additional_instructions) {
@@ -152,6 +151,10 @@ export class StandardGraph extends Graph<
152
151
  this.messageIdsByStepKey = resetIfNotEmpty(this.messageIdsByStepKey, new Map());
153
152
  this.messageStepHasToolCalls = resetIfNotEmpty(this.prelimMessageIdsByStepKey, new Map());
154
153
  this.prelimMessageIdsByStepKey = resetIfNotEmpty(this.prelimMessageIdsByStepKey, new Map());
154
+ this.reasoningKey = resetIfNotEmpty(this.reasoningKey, 'reasoning_content');
155
+ this.currentTokenType = resetIfNotEmpty(this.currentTokenType, ContentTypes.TEXT);
156
+ this.lastToken = resetIfNotEmpty(this.lastToken, undefined);
157
+ this.tokenTypeSwitch = resetIfNotEmpty(this.tokenTypeSwitch, undefined);
155
158
  }
156
159
 
157
160
  /* Run Step Processing */
@@ -208,13 +211,18 @@ export class StandardGraph extends Graph<
208
211
  getKeyList(metadata: Record<string, unknown> | undefined): (string | number | undefined)[] {
209
212
  if (!metadata) return [];
210
213
 
211
- return [
214
+ const keyList = [
212
215
  metadata.run_id as string,
213
216
  metadata.thread_id as string,
214
217
  metadata.langgraph_node as string,
215
218
  metadata.langgraph_step as number,
216
219
  metadata.checkpoint_ns as string,
217
220
  ];
221
+ if (this.currentTokenType === ContentTypes.THINK) {
222
+ keyList.push('reasoning');
223
+ }
224
+
225
+ return keyList;
218
226
  }
219
227
 
220
228
  checkKeyList(keyList: (string | number | undefined)[]): boolean {
@@ -288,6 +296,9 @@ export class StandardGraph extends Graph<
288
296
 
289
297
  return (model as t.ModelWithTools).bindTools(this.tools);
290
298
  }
299
+ overrideTestModel(responses: string[], sleep?: number): void {
300
+ this.boundModel = createFakeStreamingLLM(responses, sleep);
301
+ }
291
302
 
292
303
  getNewModel({
293
304
  clientOptions = {},
@@ -512,4 +523,15 @@ export class StandardGraph extends Graph<
512
523
  };
513
524
  dispatchCustomEvent(GraphEvents.ON_MESSAGE_DELTA, messageDelta, this.config);
514
525
  }
526
+
527
+ dispatchReasoningDelta = (stepId: string, delta: t.ReasoningDelta): void => {
528
+ if (!this.config) {
529
+ throw new Error('No config provided');
530
+ }
531
+ const reasoningDelta: t.ReasoningDeltaEvent = {
532
+ id: stepId,
533
+ delta,
534
+ };
535
+ dispatchCustomEvent(GraphEvents.ON_REASONING_DELTA, reasoningDelta, this.config);
536
+ };
515
537
  }
@@ -0,0 +1,83 @@
1
+ import type { BaseMessage } from '@langchain/core/messages';
2
+ import type { ChatGenerationChunk } from '@langchain/core/outputs';
3
+ import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
4
+ import { FakeListChatModel } from '@langchain/core/utils/testing';
5
+
6
+ type SplitStrategy = {
7
+ type: 'regex' | 'fixed';
8
+ value: RegExp | number;
9
+ };
10
+
11
+ export class FakeChatModel extends FakeListChatModel {
12
+ private splitStrategy: SplitStrategy;
13
+
14
+ constructor({
15
+ responses,
16
+ sleep,
17
+ emitCustomEvent,
18
+ splitStrategy = { type: 'regex', value: /(?<=\s+)|(?=\s+)/ }
19
+ }: {
20
+ responses: string[];
21
+ sleep?: number;
22
+ emitCustomEvent?: boolean;
23
+ splitStrategy?: SplitStrategy;
24
+ }) {
25
+ super({ responses, sleep, emitCustomEvent });
26
+ this.splitStrategy = splitStrategy;
27
+ }
28
+
29
+ private splitText(text: string): string[] {
30
+ if (this.splitStrategy.type === 'regex') {
31
+ return text.split(this.splitStrategy.value as RegExp);
32
+ } else {
33
+ const chunkSize = this.splitStrategy.value as number;
34
+ const chunks: string[] = [];
35
+ for (let i = 0; i < text.length; i += chunkSize) {
36
+ chunks.push(text.slice(i, i + chunkSize));
37
+ }
38
+ return chunks;
39
+ }
40
+ }
41
+
42
+ async *_streamResponseChunks(
43
+ _messages: BaseMessage[],
44
+ options: this['ParsedCallOptions'],
45
+ runManager?: CallbackManagerForLLMRun
46
+ ): AsyncGenerator<ChatGenerationChunk> {
47
+ const response = this._currentResponse();
48
+ this._incrementResponse();
49
+
50
+ if (this.emitCustomEvent) {
51
+ await runManager?.handleCustomEvent('some_test_event', {
52
+ someval: true,
53
+ });
54
+ }
55
+
56
+ const chunks = this.splitText(response);
57
+
58
+ for await (const chunk of chunks) {
59
+ await this._sleepIfRequested();
60
+
61
+ if (options.thrownErrorString != null && options.thrownErrorString) {
62
+ throw new Error(options.thrownErrorString);
63
+ }
64
+
65
+ const responseChunk = this._createResponseChunk(chunk);
66
+ yield responseChunk;
67
+ void runManager?.handleLLMNewToken(chunk);
68
+ }
69
+ }
70
+ }
71
+
72
+ export function createFakeStreamingLLM(
73
+ responses: string[],
74
+ sleep?: number,
75
+ splitStrategy?: SplitStrategy
76
+ ): FakeChatModel {
77
+ return new FakeChatModel({
78
+ sleep,
79
+ responses,
80
+ emitCustomEvent: true,
81
+ splitStrategy,
82
+ });
83
+ }
@@ -1,25 +1,27 @@
1
1
  // src/llm/providers.ts
2
2
  import { ChatOllama } from '@langchain/ollama';
3
+ import { ChatDeepSeek } from '@langchain/deepseek';
4
+ import { ChatMistralAI } from '@langchain/mistralai';
3
5
  import { ChatBedrockConverse } from '@langchain/aws';
4
6
  // import { ChatAnthropic } from '@langchain/anthropic';
5
- import { ChatMistralAI } from '@langchain/mistralai';
6
7
  import { ChatVertexAI } from '@langchain/google-vertexai';
7
8
  import { ChatOpenAI, AzureChatOpenAI } from '@langchain/openai';
8
9
  import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
9
10
  import { BedrockChat } from '@langchain/community/chat_models/bedrock/web';
10
11
  import type { ChatModelConstructorMap, ProviderOptionsMap, ChatModelMap } from '@/types';
11
- import { Providers } from '@/common';
12
12
  import { CustomAnthropic } from '@/llm/anthropic/llm';
13
+ import { Providers } from '@/common';
13
14
 
14
15
  export const llmProviders: Partial<ChatModelConstructorMap> = {
15
16
  [Providers.OPENAI]: ChatOpenAI,
16
- [Providers.AZURE]: AzureChatOpenAI,
17
17
  [Providers.OLLAMA]: ChatOllama,
18
+ [Providers.AZURE]: AzureChatOpenAI,
18
19
  [Providers.VERTEXAI]: ChatVertexAI,
19
- [Providers.BEDROCK_LEGACY]: BedrockChat,
20
+ [Providers.DEEPSEEK]: ChatDeepSeek,
20
21
  [Providers.MISTRALAI]: ChatMistralAI,
21
- [Providers.BEDROCK]: ChatBedrockConverse,
22
22
  [Providers.ANTHROPIC]: CustomAnthropic,
23
+ [Providers.BEDROCK_LEGACY]: BedrockChat,
24
+ [Providers.BEDROCK]: ChatBedrockConverse,
23
25
  // [Providers.ANTHROPIC]: ChatAnthropic,
24
26
  [Providers.GOOGLE]: ChatGoogleGenerativeAI,
25
27
  };
package/src/run.ts CHANGED
@@ -56,19 +56,15 @@ export class Run<T extends t.BaseGraphState> {
56
56
  }
57
57
 
58
58
  private createStandardGraph(config: t.StandardGraphConfig): t.CompiledWorkflow<t.IState, Partial<t.IState>, string> {
59
- const { llmConfig, instructions, additional_instructions, signal, streamBuffer, toolEnd, tools = [] } = config;
59
+ const { llmConfig, tools = [], ...graphInput } = config;
60
60
  const { provider, ...clientOptions } = llmConfig;
61
61
 
62
62
  const standardGraph = new StandardGraph({
63
- runId: this.id,
64
63
  tools,
65
64
  provider,
66
- signal,
67
- instructions,
68
65
  clientOptions,
69
- additional_instructions,
70
- streamBuffer,
71
- toolEnd,
66
+ ...graphInput,
67
+ runId: this.id,
72
68
  });
73
69
  this.Graph = standardGraph;
74
70
  return standardGraph.createWorkflow();
@@ -12,10 +12,12 @@ import { GraphEvents } from '@/common';
12
12
  import { Run } from '@/run';
13
13
 
14
14
  const conversationHistory: BaseMessage[] = [];
15
+ let _contentParts: t.MessageContentComplex[] = [];
15
16
 
16
17
  async function testStandardStreaming(): Promise<void> {
17
18
  const { userName, location, provider, currentDate } = await getArgs();
18
19
  const { contentParts, aggregateContent } = createContentAggregator();
20
+ _contentParts = contentParts as t.MessageContentComplex[];
19
21
  const customHandlers = {
20
22
  [GraphEvents.TOOL_END]: new ToolEndHandler(),
21
23
  [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
@@ -48,6 +50,13 @@ async function testStandardStreaming(): Promise<void> {
48
50
  aggregateContent({ event, data: data as t.MessageDeltaEvent });
49
51
  }
50
52
  },
53
+ [GraphEvents.ON_REASONING_DELTA]: {
54
+ handle: (event: GraphEvents.ON_REASONING_DELTA, data: t.StreamEventData): void => {
55
+ console.log('====== ON_REASONING_DELTA ======');
56
+ console.dir(data, { depth: null });
57
+ aggregateContent({ event, data: data as t.ReasoningDeltaEvent });
58
+ }
59
+ },
51
60
  [GraphEvents.TOOL_START]: {
52
61
  handle: (_event: string, data: t.StreamEventData, metadata?: Record<string, unknown>): void => {
53
62
  console.log('====== TOOL_START ======');
@@ -63,7 +72,7 @@ async function testStandardStreaming(): Promise<void> {
63
72
  graphConfig: {
64
73
  type: 'standard',
65
74
  llmConfig,
66
- tools: [new TavilySearchResults()],
75
+ // tools: [new TavilySearchResults()],
67
76
  instructions: 'You are a friendly AI assistant. Always address the user by their name.',
68
77
  additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
69
78
  },
@@ -81,7 +90,7 @@ async function testStandardStreaming(): Promise<void> {
81
90
 
82
91
  console.log('Test 1: Simple message test');
83
92
 
84
- const userMessage = `hi tell me a long story`;
93
+ const userMessage = `hi`;
85
94
 
86
95
  conversationHistory.push(new HumanMessage(userMessage));
87
96
 
@@ -97,23 +106,26 @@ async function testStandardStreaming(): Promise<void> {
97
106
  // console.dir(finalContentParts, { depth: null });
98
107
  console.log('\n\n====================\n\n');
99
108
  console.dir(contentParts, { depth: null });
100
- const { handleLLMEnd, collected } = createMetadataAggregator();
101
- const titleResult = await run.generateTitle({
102
- inputText: userMessage,
103
- contentParts,
104
- chainOptions: {
105
- callbacks: [{
106
- handleLLMEnd,
107
- }],
108
- },
109
- });
110
- console.log('Generated Title:', titleResult);
111
- console.log('Collected metadata:', collected);
109
+ // const { handleLLMEnd, collected } = createMetadataAggregator();
110
+ // const titleResult = await run.generateTitle({
111
+ // inputText: userMessage,
112
+ // contentParts,
113
+ // chainOptions: {
114
+ // callbacks: [{
115
+ // handleLLMEnd,
116
+ // }],
117
+ // },
118
+ // });
119
+ // console.log('Generated Title:', titleResult);
120
+ // console.log('Collected metadata:', collected);
112
121
  }
113
122
 
114
123
  process.on('unhandledRejection', (reason, promise) => {
115
124
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
116
125
  console.log('Conversation history:');
126
+ console.dir(conversationHistory, { depth: null });
127
+ console.log('Content parts:');
128
+ console.dir(_contentParts, { depth: null });
117
129
  process.exit(1);
118
130
  });
119
131
 
@@ -125,5 +137,7 @@ testStandardStreaming().catch((err) => {
125
137
  console.error(err);
126
138
  console.log('Conversation history:');
127
139
  console.dir(conversationHistory, { depth: null });
140
+ console.log('Content parts:');
141
+ console.dir(_contentParts, { depth: null });
128
142
  process.exit(1);
129
143
  });