@librechat/agents 1.8.7 → 1.8.9
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 +8 -1
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/llm.cjs +117 -0
- package/dist/cjs/llm/anthropic/llm.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +277 -0
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +135 -0
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +5 -4
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/text.cjs +58 -0
- package/dist/cjs/llm/text.cjs.map +1 -0
- package/dist/cjs/main.cjs +3 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages.cjs +14 -54
- package/dist/cjs/messages.cjs.map +1 -1
- package/dist/cjs/stream.cjs +63 -48
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +20 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/utils/misc.cjs +49 -0
- package/dist/cjs/utils/misc.cjs.map +1 -0
- package/dist/esm/common/enum.mjs +1 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +8 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/llm/anthropic/llm.mjs +115 -0
- package/dist/esm/llm/anthropic/llm.mjs.map +1 -0
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +274 -0
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -0
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +133 -0
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +5 -4
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/text.mjs +56 -0
- package/dist/esm/llm/text.mjs.map +1 -0
- package/dist/esm/main.mjs +2 -1
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages.mjs +14 -54
- package/dist/esm/messages.mjs.map +1 -1
- package/dist/esm/stream.mjs +63 -49
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +22 -7
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/utils/misc.mjs +47 -0
- package/dist/esm/utils/misc.mjs.map +1 -0
- package/dist/types/common/enum.d.ts +2 -1
- package/dist/types/llm/anthropic/types.d.ts +4 -0
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
- package/dist/types/llm/text.d.ts +6 -6
- package/dist/types/stream.d.ts +2 -0
- package/dist/types/types/llm.d.ts +6 -1
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/misc.d.ts +6 -0
- package/package.json +8 -7
- package/src/common/enum.ts +1 -0
- package/src/events.ts +9 -1
- package/src/llm/anthropic/llm.ts +1 -1
- package/src/llm/anthropic/types.ts +7 -1
- package/src/llm/anthropic/utils/message_inputs.ts +86 -8
- package/src/llm/providers.ts +6 -4
- package/src/llm/text.ts +30 -45
- package/src/messages.ts +14 -65
- package/src/scripts/args.ts +1 -1
- package/src/scripts/code_exec.ts +4 -0
- package/src/scripts/simple.ts +4 -0
- package/src/stream.ts +68 -50
- package/src/tools/ToolNode.ts +25 -9
- package/src/types/llm.ts +6 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/llmConfig.ts +6 -0
- package/src/utils/misc.ts +45 -0
package/src/stream.ts
CHANGED
|
@@ -33,6 +33,73 @@ const getMessageId = (stepKey: string, graph: Graph<t.BaseGraphState>, returnExi
|
|
|
33
33
|
return message_id;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
export const handleToolCalls = (toolCalls?: ToolCall[], metadata?: Record<string, unknown>, graph?: Graph): void => {
|
|
37
|
+
if (!graph || !metadata) {
|
|
38
|
+
console.warn(`Graph or metadata not found in ${event} event`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!toolCalls) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (toolCalls.length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const tool_calls: ToolCall[] = [];
|
|
51
|
+
const tool_call_ids: string[] = [];
|
|
52
|
+
for (const tool_call of toolCalls) {
|
|
53
|
+
const toolCallId = tool_call.id ?? `toolu_${nanoid()}`;
|
|
54
|
+
tool_call.id = toolCallId;
|
|
55
|
+
if (!toolCallId || graph.toolCallStepIds.has(toolCallId)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
tool_calls.push(tool_call);
|
|
60
|
+
tool_call_ids.push(toolCallId);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const stepKey = graph.getStepKey(metadata);
|
|
64
|
+
|
|
65
|
+
let prevStepId = '';
|
|
66
|
+
let prevRunStep: t.RunStep | undefined;
|
|
67
|
+
try {
|
|
68
|
+
prevStepId = graph.getStepIdByKey(stepKey, graph.contentData.length - 1);
|
|
69
|
+
prevRunStep = graph.getRunStep(prevStepId);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
// no previous step
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const dispatchToolCallIds = (lastMessageStepId: string): void => {
|
|
75
|
+
graph.dispatchMessageDelta(lastMessageStepId, {
|
|
76
|
+
content: [{
|
|
77
|
+
type: 'text',
|
|
78
|
+
text: '',
|
|
79
|
+
tool_call_ids,
|
|
80
|
+
}],
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
/* If the previous step exists and is a message creation */
|
|
84
|
+
if (prevStepId && prevRunStep && prevRunStep.type === StepTypes.MESSAGE_CREATION) {
|
|
85
|
+
dispatchToolCallIds(prevStepId);
|
|
86
|
+
/* If the previous step doesn't exist or is not a message creation */
|
|
87
|
+
} else if (!prevRunStep || prevRunStep.type !== StepTypes.MESSAGE_CREATION) {
|
|
88
|
+
const messageId = getMessageId(stepKey, graph, true) ?? '';
|
|
89
|
+
const stepId = graph.dispatchRunStep(stepKey, {
|
|
90
|
+
type: StepTypes.MESSAGE_CREATION,
|
|
91
|
+
message_creation: {
|
|
92
|
+
message_id: messageId,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
dispatchToolCallIds(stepId);
|
|
96
|
+
}
|
|
97
|
+
graph.dispatchRunStep(stepKey, {
|
|
98
|
+
type: StepTypes.TOOL_CALLS,
|
|
99
|
+
tool_calls,
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
36
103
|
export class ChatModelStreamHandler implements t.EventHandler {
|
|
37
104
|
handle(event: string, data: t.StreamEventData, metadata?: Record<string, unknown>, graph?: Graph): void {
|
|
38
105
|
if (!graph) {
|
|
@@ -56,56 +123,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
56
123
|
|
|
57
124
|
if (chunk.tool_calls && chunk.tool_calls.length > 0 && chunk.tool_calls.every((tc) => tc.id)) {
|
|
58
125
|
hasToolCalls = true;
|
|
59
|
-
|
|
60
|
-
const tool_call_ids: string[] = [];
|
|
61
|
-
for (const tool_call of chunk.tool_calls) {
|
|
62
|
-
const toolCallId = tool_call.id ?? '';
|
|
63
|
-
if (!toolCallId || graph.toolCallStepIds.has(toolCallId)) {
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
tool_calls.push(tool_call);
|
|
68
|
-
tool_call_ids.push(toolCallId);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const stepKey = graph.getStepKey(metadata);
|
|
72
|
-
|
|
73
|
-
let prevStepId = '';
|
|
74
|
-
let prevRunStep: t.RunStep | undefined;
|
|
75
|
-
try {
|
|
76
|
-
prevStepId = graph.getStepIdByKey(stepKey, graph.contentData.length - 1);
|
|
77
|
-
prevRunStep = graph.getRunStep(prevStepId);
|
|
78
|
-
} catch (e) {
|
|
79
|
-
// no previous step
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const dispatchToolCallIds = (lastMessageStepId: string): void => {
|
|
83
|
-
graph.dispatchMessageDelta(lastMessageStepId, {
|
|
84
|
-
content: [{
|
|
85
|
-
type: 'text',
|
|
86
|
-
text: '',
|
|
87
|
-
tool_call_ids,
|
|
88
|
-
}],
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
/* If the previous step exists and is a message creation */
|
|
92
|
-
if (prevStepId && prevRunStep && prevRunStep.type === StepTypes.MESSAGE_CREATION) {
|
|
93
|
-
dispatchToolCallIds(prevStepId);
|
|
94
|
-
/* If the previous step doesn't exist or is not a message creation */
|
|
95
|
-
} else if (!prevRunStep || prevRunStep.type !== StepTypes.MESSAGE_CREATION) {
|
|
96
|
-
const messageId = getMessageId(stepKey, graph, true) ?? '';
|
|
97
|
-
const stepId = graph.dispatchRunStep(stepKey, {
|
|
98
|
-
type: StepTypes.MESSAGE_CREATION,
|
|
99
|
-
message_creation: {
|
|
100
|
-
message_id: messageId,
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
dispatchToolCallIds(stepId);
|
|
104
|
-
}
|
|
105
|
-
graph.dispatchRunStep(stepKey, {
|
|
106
|
-
type: StepTypes.TOOL_CALLS,
|
|
107
|
-
tool_calls,
|
|
108
|
-
});
|
|
126
|
+
handleToolCalls(chunk.tool_calls, metadata, graph);
|
|
109
127
|
}
|
|
110
128
|
|
|
111
129
|
const isEmptyContent = typeof content === 'undefined' || !content.length || typeof content === 'string' && !content;
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { END, MessagesAnnotation } from '@langchain/langgraph';
|
|
1
|
+
import { END, MessagesAnnotation, isCommand, isGraphInterrupt } from '@langchain/langgraph';
|
|
2
2
|
import { ToolMessage, isBaseMessage } from '@langchain/core/messages';
|
|
3
3
|
import type { RunnableConfig, RunnableToolLike } from '@langchain/core/runnables';
|
|
4
4
|
import type { BaseMessage, AIMessage } from '@langchain/core/messages';
|
|
5
5
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
6
6
|
import type * as t from '@/types';
|
|
7
|
-
import{ RunnableCallable } from '@/utils';
|
|
8
|
-
import { GraphNodeKeys } from '@/common';
|
|
7
|
+
import{ RunnableCallable, unescapeObject } from '@/utils';
|
|
8
|
+
import { GraphNodeKeys, Providers } from '@/common';
|
|
9
9
|
|
|
10
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
11
|
export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
@@ -46,7 +46,6 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
46
46
|
this.tools = tools;
|
|
47
47
|
this.toolMap = toolMap ?? new Map(tools.map(tool => [tool.name, tool]));
|
|
48
48
|
}
|
|
49
|
-
|
|
50
49
|
const outputs = await Promise.all(
|
|
51
50
|
(message as AIMessage).tool_calls?.map(async (call) => {
|
|
52
51
|
const tool = this.toolMap.get(call.name);
|
|
@@ -54,11 +53,15 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
54
53
|
if (tool === undefined) {
|
|
55
54
|
throw new Error(`Tool "${call.name}" not found.`);
|
|
56
55
|
}
|
|
56
|
+
const args = config.metadata?.provider === Providers.GOOGLE ? unescapeObject(call.args) : call.args;
|
|
57
57
|
const output = await tool.invoke(
|
|
58
|
-
{ ...call, type: 'tool_call' },
|
|
58
|
+
{ ...call, args, type: 'tool_call' },
|
|
59
59
|
config
|
|
60
60
|
);
|
|
61
|
-
if (
|
|
61
|
+
if (
|
|
62
|
+
(isBaseMessage(output) && output._getType() === 'tool') ||
|
|
63
|
+
isCommand(output)
|
|
64
|
+
) {
|
|
62
65
|
return output;
|
|
63
66
|
} else {
|
|
64
67
|
return new ToolMessage({
|
|
@@ -68,11 +71,14 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
68
71
|
tool_call_id: call.id!,
|
|
69
72
|
});
|
|
70
73
|
}
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
} catch (_e: unknown) {
|
|
75
|
+
const e = _e as Error;
|
|
73
76
|
if (!this.handleToolErrors) {
|
|
74
77
|
throw e;
|
|
75
78
|
}
|
|
79
|
+
if (isGraphInterrupt(e)) {
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
76
82
|
return new ToolMessage({
|
|
77
83
|
content: `Error: ${e.message}\n Please fix your mistakes.`,
|
|
78
84
|
name: call.name,
|
|
@@ -82,7 +88,17 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
82
88
|
}) ?? []
|
|
83
89
|
);
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
if (!outputs.some(isCommand)) {
|
|
92
|
+
return (Array.isArray(input) ? outputs : { messages: outputs }) as T;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const combinedOutputs = outputs.map((output) => {
|
|
96
|
+
if (isCommand(output)) {
|
|
97
|
+
return output;
|
|
98
|
+
}
|
|
99
|
+
return Array.isArray(input) ? [output] : { messages: [output] };
|
|
100
|
+
});
|
|
101
|
+
return combinedOutputs as T;
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
104
|
|
package/src/types/llm.ts
CHANGED
|
@@ -6,12 +6,14 @@ import { ChatMistralAI } from '@langchain/mistralai';
|
|
|
6
6
|
import { ChatBedrockConverse } from '@langchain/aws';
|
|
7
7
|
import { ChatVertexAI } from '@langchain/google-vertexai';
|
|
8
8
|
import { BedrockChat } from '@langchain/community/chat_models/bedrock/web';
|
|
9
|
+
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
|
|
9
10
|
import type { Runnable } from '@langchain/core/runnables';
|
|
10
11
|
import type { StructuredTool } from '@langchain/core/tools';
|
|
11
12
|
import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
|
|
12
13
|
import type { BedrockChatFields } from '@langchain/community/chat_models/bedrock/web';
|
|
13
14
|
import type { ChatOpenAIFields } from '@langchain/openai';
|
|
14
15
|
import type { OpenAI as OpenAIClient } from 'openai';
|
|
16
|
+
import type { GoogleGenerativeAIChatInput } from '@langchain/google-genai';
|
|
15
17
|
import type { ChatVertexAIInput } from '@langchain/google-vertexai';
|
|
16
18
|
import type { ChatBedrockConverseInput } from '@langchain/aws';
|
|
17
19
|
import type { ChatMistralAIInput } from '@langchain/mistralai';
|
|
@@ -29,8 +31,9 @@ export type MistralAIClientOptions = ChatMistralAIInput;
|
|
|
29
31
|
export type VertexAIClientOptions = ChatVertexAIInput;
|
|
30
32
|
export type BedrockClientOptions = BedrockChatFields;
|
|
31
33
|
export type BedrockConverseClientOptions = ChatBedrockConverseInput;
|
|
34
|
+
export type GoogleClientOptions = GoogleGenerativeAIChatInput;
|
|
32
35
|
|
|
33
|
-
export type ClientOptions = OpenAIClientOptions | OllamaClientOptions | AnthropicClientOptions | MistralAIClientOptions | VertexAIClientOptions | BedrockClientOptions | BedrockConverseClientOptions;
|
|
36
|
+
export type ClientOptions = OpenAIClientOptions | OllamaClientOptions | AnthropicClientOptions | MistralAIClientOptions | VertexAIClientOptions | BedrockClientOptions | BedrockConverseClientOptions | GoogleClientOptions;
|
|
34
37
|
|
|
35
38
|
export type LLMConfig = {
|
|
36
39
|
provider: Providers;
|
|
@@ -44,6 +47,7 @@ export type ProviderOptionsMap = {
|
|
|
44
47
|
[Providers.VERTEXAI]: VertexAIClientOptions;
|
|
45
48
|
[Providers.BEDROCK_LEGACY]: BedrockClientOptions;
|
|
46
49
|
[Providers.BEDROCK]: BedrockConverseClientOptions;
|
|
50
|
+
[Providers.GOOGLE]: GoogleClientOptions;
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
export type ChatModelMap = {
|
|
@@ -54,6 +58,7 @@ export type ChatModelMap = {
|
|
|
54
58
|
[Providers.VERTEXAI]: ChatVertexAI;
|
|
55
59
|
[Providers.BEDROCK_LEGACY]: BedrockChat;
|
|
56
60
|
[Providers.BEDROCK]: ChatBedrockConverse;
|
|
61
|
+
[Providers.GOOGLE]: ChatGoogleGenerativeAI;
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
export type ChatModelConstructorMap = {
|
package/src/utils/index.ts
CHANGED
package/src/utils/llmConfig.ts
CHANGED
|
@@ -35,6 +35,12 @@ const llmConfigs: Record<string, t.LLMConfig | undefined> = {
|
|
|
35
35
|
streaming: true,
|
|
36
36
|
streamUsage: true,
|
|
37
37
|
},
|
|
38
|
+
[Providers.GOOGLE]: {
|
|
39
|
+
provider: Providers.GOOGLE,
|
|
40
|
+
model: 'gemini-2.0-flash-exp',
|
|
41
|
+
streaming: true,
|
|
42
|
+
streamUsage: true,
|
|
43
|
+
},
|
|
38
44
|
[Providers.BEDROCK]: {
|
|
39
45
|
provider: Providers.BEDROCK,
|
|
40
46
|
model: 'anthropic.claude-3-sonnet-20240229-v1:0',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unescapes a c-escaped string
|
|
3
|
+
* @param str The string to unescape
|
|
4
|
+
* @returns The unescaped string
|
|
5
|
+
*/
|
|
6
|
+
const unescapeString = (string: string): string => string.replace(/\\(.)/g, (_, char) => {
|
|
7
|
+
switch (char) {
|
|
8
|
+
case 'n':
|
|
9
|
+
return '\n';
|
|
10
|
+
case 't':
|
|
11
|
+
return '\t';
|
|
12
|
+
case 'r':
|
|
13
|
+
return '\r';
|
|
14
|
+
case '"':
|
|
15
|
+
return '"';
|
|
16
|
+
case '\'':
|
|
17
|
+
return '\'';
|
|
18
|
+
case '\\':
|
|
19
|
+
return '\\';
|
|
20
|
+
default:
|
|
21
|
+
return char;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Recursively unescapes all string values in an object
|
|
27
|
+
* @param obj The object to unescape
|
|
28
|
+
* @returns The unescaped object
|
|
29
|
+
*/
|
|
30
|
+
export function unescapeObject(obj: unknown, key?: string): unknown {
|
|
31
|
+
if (typeof obj === 'string') {
|
|
32
|
+
let unescaped = unescapeString(obj);
|
|
33
|
+
if (key === 'filePath' && unescaped.match(/^"(.+)"$/)) {
|
|
34
|
+
unescaped = unescaped.substring(1, unescaped.length - 1);
|
|
35
|
+
}
|
|
36
|
+
return unescaped;
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(obj)) {
|
|
39
|
+
return obj.map((value) => unescapeObject(value, key === 'contextPaths' ? 'filePath' : ''));
|
|
40
|
+
}
|
|
41
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
42
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, unescapeObject(value, key)]));
|
|
43
|
+
}
|
|
44
|
+
return obj;
|
|
45
|
+
}
|