@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.
- package/dist/cjs/common/enum.cjs +1 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -0
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +34 -5
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/llm.cjs +1 -3
- package/dist/cjs/llm/anthropic/llm.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/fake.cjs +55 -0
- package/dist/cjs/llm/fake.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +7 -5
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/text.cjs.map +1 -1
- package/dist/cjs/messages.cjs.map +1 -1
- package/dist/cjs/run.cjs +3 -7
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/splitStream.cjs.map +1 -1
- package/dist/cjs/stream.cjs +93 -55
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +8 -2
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/utils/graph.cjs.map +1 -1
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/misc.cjs.map +1 -1
- package/dist/cjs/utils/run.cjs.map +1 -1
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/esm/common/enum.mjs +1 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -0
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +35 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/llm.mjs +1 -3
- package/dist/esm/llm/anthropic/llm.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/fake.mjs +52 -0
- package/dist/esm/llm/fake.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +8 -6
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/text.mjs.map +1 -1
- package/dist/esm/messages.mjs.map +1 -1
- package/dist/esm/run.mjs +3 -7
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/splitStream.mjs.map +1 -1
- package/dist/esm/stream.mjs +94 -56
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +9 -3
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/utils/graph.mjs.map +1 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/misc.mjs.map +1 -1
- package/dist/esm/utils/run.mjs.map +1 -1
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/types/common/enum.d.ts +2 -1
- package/dist/types/events.d.ts +4 -1
- package/dist/types/graphs/Graph.d.ts +9 -13
- package/dist/types/llm/fake.d.ts +21 -0
- package/dist/types/specs/spec.utils.d.ts +1 -0
- package/dist/types/stream.d.ts +9 -13
- package/dist/types/types/graph.d.ts +16 -0
- package/dist/types/types/llm.d.ts +10 -5
- package/dist/types/types/run.d.ts +4 -12
- package/dist/types/types/stream.d.ts +12 -0
- package/package.json +15 -26
- package/src/common/enum.ts +1 -0
- package/src/events.ts +13 -1
- package/src/graphs/Graph.ts +43 -21
- package/src/llm/fake.ts +83 -0
- package/src/llm/providers.ts +7 -5
- package/src/run.ts +3 -7
- package/src/scripts/simple.ts +28 -14
- package/src/specs/anthropic.simple.test.ts +204 -0
- package/src/specs/openai.simple.test.ts +204 -0
- package/src/specs/reasoning.test.ts +165 -0
- package/src/specs/spec.utils.ts +3 -0
- package/src/stream.ts +100 -72
- package/src/tools/CodeExecutor.ts +8 -2
- package/src/types/graph.ts +18 -1
- package/src/types/llm.ts +10 -5
- package/src/types/run.ts +5 -13
- package/src/types/stream.ts +14 -1
- 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.
|
|
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 '
|
|
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 '
|
|
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.
|
|
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": "^
|
|
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": "^
|
|
116
|
-
"@typescript-eslint/parser": "^
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
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
|
-
"
|
|
128
|
-
"
|
|
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",
|
package/src/common/enum.ts
CHANGED
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,
|
|
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) => {
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/llm/fake.ts
ADDED
|
@@ -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
|
+
}
|
package/src/llm/providers.ts
CHANGED
|
@@ -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.
|
|
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,
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
toolEnd,
|
|
66
|
+
...graphInput,
|
|
67
|
+
runId: this.id,
|
|
72
68
|
});
|
|
73
69
|
this.Graph = standardGraph;
|
|
74
70
|
return standardGraph.createWorkflow();
|
package/src/scripts/simple.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
});
|