@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
|
@@ -18,3 +18,7 @@ export type AnthropicToolChoice = {
|
|
|
18
18
|
name: string;
|
|
19
19
|
} | 'any' | 'auto' | 'none' | string;
|
|
20
20
|
export type ChatAnthropicToolType = AnthropicTool | BindToolsInput;
|
|
21
|
+
export type AnthropicTextBlockParam = Anthropic.Messages.TextBlockParam;
|
|
22
|
+
export type AnthropicImageBlockParam = Anthropic.Messages.ImageBlockParam;
|
|
23
|
+
export type AnthropicToolUseBlockParam = Anthropic.Messages.ToolUseBlockParam;
|
|
24
|
+
export type AnthropicToolResultBlockParam = Anthropic.Messages.ToolResultBlockParam;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { BaseMessage } from '@langchain/core/messages';
|
|
5
5
|
import { ToolCall } from '@langchain/core/messages/tool';
|
|
6
|
-
import type {
|
|
6
|
+
import type { AnthropicToolResponse, AnthropicMessageCreateParams } from '@/llm/anthropic/types';
|
|
7
7
|
export declare function _convertLangChainToolCallToAnthropic(toolCall: ToolCall): AnthropicToolResponse;
|
|
8
8
|
/**
|
|
9
9
|
* Formats messages as a prompt for the model.
|
package/dist/types/llm/text.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
import type { ReadableOptions } from 'stream';
|
|
3
|
-
export interface TextStreamOptions extends ReadableOptions {
|
|
1
|
+
export interface TextStreamOptions {
|
|
4
2
|
minChunkSize?: number;
|
|
5
3
|
maxChunkSize?: number;
|
|
6
4
|
delay?: number;
|
|
5
|
+
firstWordChunk?: boolean;
|
|
7
6
|
}
|
|
8
7
|
export type ProgressCallback = (chunk: string) => void;
|
|
9
8
|
export type PostChunkCallback = (chunk: string) => void;
|
|
10
|
-
export declare class TextStream
|
|
9
|
+
export declare class TextStream {
|
|
11
10
|
private text;
|
|
12
11
|
private currentIndex;
|
|
13
12
|
private minChunkSize;
|
|
14
13
|
private maxChunkSize;
|
|
15
14
|
private delay;
|
|
15
|
+
private firstWordChunk;
|
|
16
16
|
constructor(text: string, options?: TextStreamOptions);
|
|
17
|
-
_read(): void;
|
|
18
17
|
private randomInt;
|
|
19
|
-
|
|
18
|
+
private static readonly BOUNDARIES;
|
|
19
|
+
private findFirstWordBoundary;
|
|
20
20
|
generateText(progressCallback?: ProgressCallback): AsyncGenerator<string, void, unknown>;
|
|
21
21
|
}
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
1
2
|
import type { Graph } from '@/graphs';
|
|
2
3
|
import type * as t from '@/types';
|
|
3
4
|
import { GraphEvents } from '@/common';
|
|
5
|
+
export declare const handleToolCalls: (toolCalls?: ToolCall[], metadata?: Record<string, unknown>, graph?: Graph) => void;
|
|
4
6
|
export declare class ChatModelStreamHandler implements t.EventHandler {
|
|
5
7
|
handle(event: string, data: t.StreamEventData, metadata?: Record<string, unknown>, graph?: Graph): void;
|
|
6
8
|
}
|
|
@@ -5,12 +5,14 @@ import { ChatMistralAI } from '@langchain/mistralai';
|
|
|
5
5
|
import { ChatBedrockConverse } from '@langchain/aws';
|
|
6
6
|
import { ChatVertexAI } from '@langchain/google-vertexai';
|
|
7
7
|
import { BedrockChat } from '@langchain/community/chat_models/bedrock/web';
|
|
8
|
+
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
|
|
8
9
|
import type { Runnable } from '@langchain/core/runnables';
|
|
9
10
|
import type { StructuredTool } from '@langchain/core/tools';
|
|
10
11
|
import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
|
|
11
12
|
import type { BedrockChatFields } from '@langchain/community/chat_models/bedrock/web';
|
|
12
13
|
import type { ChatOpenAIFields } from '@langchain/openai';
|
|
13
14
|
import type { OpenAI as OpenAIClient } from 'openai';
|
|
15
|
+
import type { GoogleGenerativeAIChatInput } from '@langchain/google-genai';
|
|
14
16
|
import type { ChatVertexAIInput } from '@langchain/google-vertexai';
|
|
15
17
|
import type { ChatBedrockConverseInput } from '@langchain/aws';
|
|
16
18
|
import type { ChatMistralAIInput } from '@langchain/mistralai';
|
|
@@ -26,7 +28,8 @@ export type MistralAIClientOptions = ChatMistralAIInput;
|
|
|
26
28
|
export type VertexAIClientOptions = ChatVertexAIInput;
|
|
27
29
|
export type BedrockClientOptions = BedrockChatFields;
|
|
28
30
|
export type BedrockConverseClientOptions = ChatBedrockConverseInput;
|
|
29
|
-
export type
|
|
31
|
+
export type GoogleClientOptions = GoogleGenerativeAIChatInput;
|
|
32
|
+
export type ClientOptions = OpenAIClientOptions | OllamaClientOptions | AnthropicClientOptions | MistralAIClientOptions | VertexAIClientOptions | BedrockClientOptions | BedrockConverseClientOptions | GoogleClientOptions;
|
|
30
33
|
export type LLMConfig = {
|
|
31
34
|
provider: Providers;
|
|
32
35
|
} & ClientOptions;
|
|
@@ -38,6 +41,7 @@ export type ProviderOptionsMap = {
|
|
|
38
41
|
[Providers.VERTEXAI]: VertexAIClientOptions;
|
|
39
42
|
[Providers.BEDROCK_LEGACY]: BedrockClientOptions;
|
|
40
43
|
[Providers.BEDROCK]: BedrockConverseClientOptions;
|
|
44
|
+
[Providers.GOOGLE]: GoogleClientOptions;
|
|
41
45
|
};
|
|
42
46
|
export type ChatModelMap = {
|
|
43
47
|
[Providers.OPENAI]: ChatOpenAI;
|
|
@@ -47,6 +51,7 @@ export type ChatModelMap = {
|
|
|
47
51
|
[Providers.VERTEXAI]: ChatVertexAI;
|
|
48
52
|
[Providers.BEDROCK_LEGACY]: BedrockChat;
|
|
49
53
|
[Providers.BEDROCK]: ChatBedrockConverse;
|
|
54
|
+
[Providers.GOOGLE]: ChatGoogleGenerativeAI;
|
|
50
55
|
};
|
|
51
56
|
export type ChatModelConstructorMap = {
|
|
52
57
|
[P in Providers]: new (config: ProviderOptionsMap[P]) => ChatModelMap[P];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@librechat/agents",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.9",
|
|
4
4
|
"main": "./dist/cjs/main.cjs",
|
|
5
5
|
"module": "./dist/esm/main.mjs",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"start:cli": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/cli.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
|
43
43
|
"content": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/content.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
|
|
44
44
|
"stream": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/stream.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
|
|
45
|
-
"code_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec.ts --provider '
|
|
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 'anthropic' --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 'anthropic' --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 'anthropic' --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
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'",
|
|
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'",
|
|
@@ -70,12 +70,13 @@
|
|
|
70
70
|
"@aws-crypto/sha256-js": "^5.2.0",
|
|
71
71
|
"@aws-sdk/credential-provider-node": "^3.613.0",
|
|
72
72
|
"@aws-sdk/types": "^3.609.0",
|
|
73
|
-
"@langchain/anthropic": "^0.3.
|
|
73
|
+
"@langchain/anthropic": "^0.3.11",
|
|
74
74
|
"@langchain/aws": "^0.1.2",
|
|
75
75
|
"@langchain/community": "^0.3.14",
|
|
76
|
-
"@langchain/core": "^0.3.
|
|
77
|
-
"@langchain/google-
|
|
78
|
-
"@langchain/
|
|
76
|
+
"@langchain/core": "^0.3.26",
|
|
77
|
+
"@langchain/google-genai": "^0.1.6",
|
|
78
|
+
"@langchain/google-vertexai": "^0.1.5",
|
|
79
|
+
"@langchain/langgraph": "^0.2.34",
|
|
79
80
|
"@langchain/mistralai": "^0.0.26",
|
|
80
81
|
"@langchain/ollama": "^0.1.1",
|
|
81
82
|
"@langchain/openai": "^0.3.14",
|
package/src/common/enum.ts
CHANGED
package/src/events.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// src/events.ts
|
|
3
3
|
import type { Graph } from '@/graphs';
|
|
4
4
|
import type * as t from '@/types';
|
|
5
|
+
import { handleToolCalls } from '@/stream';
|
|
6
|
+
import { Providers } from '@/common';
|
|
5
7
|
|
|
6
8
|
export class HandlerRegistry {
|
|
7
9
|
private handlers: Map<string, t.EventHandler> = new Map();
|
|
@@ -28,6 +30,12 @@ export class ModelEndHandler implements t.EventHandler {
|
|
|
28
30
|
console.dir({
|
|
29
31
|
usage,
|
|
30
32
|
}, { depth: null });
|
|
33
|
+
|
|
34
|
+
if (metadata.provider !== Providers.GOOGLE) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
handleToolCalls(data?.output?.tool_calls, metadata, graph);
|
|
31
39
|
}
|
|
32
40
|
}
|
|
33
41
|
|
|
@@ -58,7 +66,7 @@ export class TestLLMStreamHandler implements t.EventHandler {
|
|
|
58
66
|
handle(event: string, data: t.StreamEventData | undefined): void {
|
|
59
67
|
const chunk = data?.chunk;
|
|
60
68
|
const isMessageChunk = !!(chunk && 'message' in chunk);
|
|
61
|
-
const msg = isMessageChunk
|
|
69
|
+
const msg = isMessageChunk ? chunk.message : undefined;
|
|
62
70
|
if (msg && msg.tool_call_chunks && msg.tool_call_chunks.length > 0) {
|
|
63
71
|
console.log(msg.tool_call_chunks);
|
|
64
72
|
} else if (msg && msg.content) {
|
package/src/llm/anthropic/llm.ts
CHANGED
|
@@ -84,7 +84,7 @@ export class CustomAnthropic extends ChatAnthropicMessages {
|
|
|
84
84
|
);
|
|
85
85
|
|
|
86
86
|
for await (const data of stream) {
|
|
87
|
-
if (options.signal?.aborted) {
|
|
87
|
+
if (options.signal?.aborted === true) {
|
|
88
88
|
stream.controller.abort();
|
|
89
89
|
throw new Error('AbortError: User aborted the request.');
|
|
90
90
|
}
|
|
@@ -10,6 +10,7 @@ export type AnthropicToolResponse = {
|
|
|
10
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
11
|
input: Record<string, any>;
|
|
12
12
|
};
|
|
13
|
+
|
|
13
14
|
export type AnthropicMessageParam = Anthropic.MessageParam;
|
|
14
15
|
export type AnthropicMessageResponse =
|
|
15
16
|
| Anthropic.ContentBlock
|
|
@@ -29,4 +30,9 @@ export type AnthropicToolChoice =
|
|
|
29
30
|
| 'auto'
|
|
30
31
|
| 'none'
|
|
31
32
|
| string;
|
|
32
|
-
export type ChatAnthropicToolType = AnthropicTool | BindToolsInput;
|
|
33
|
+
export type ChatAnthropicToolType = AnthropicTool | BindToolsInput;
|
|
34
|
+
export type AnthropicTextBlockParam = Anthropic.Messages.TextBlockParam;
|
|
35
|
+
export type AnthropicImageBlockParam = Anthropic.Messages.ImageBlockParam;
|
|
36
|
+
export type AnthropicToolUseBlockParam = Anthropic.Messages.ToolUseBlockParam;
|
|
37
|
+
export type AnthropicToolResultBlockParam =
|
|
38
|
+
Anthropic.Messages.ToolResultBlockParam;
|
|
@@ -1,19 +1,25 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
/**
|
|
2
3
|
* This util file contains functions for converting LangChain messages to Anthropic messages.
|
|
3
4
|
*/
|
|
4
5
|
import {
|
|
5
|
-
BaseMessage,
|
|
6
|
-
SystemMessage,
|
|
7
|
-
HumanMessage,
|
|
8
6
|
AIMessage,
|
|
7
|
+
BaseMessage,
|
|
9
8
|
ToolMessage,
|
|
10
|
-
MessageContent,
|
|
11
9
|
isAIMessage,
|
|
10
|
+
HumanMessage,
|
|
11
|
+
SystemMessage,
|
|
12
|
+
MessageContent,
|
|
12
13
|
} from '@langchain/core/messages';
|
|
13
14
|
import { ToolCall } from '@langchain/core/messages/tool';
|
|
14
15
|
import type {
|
|
15
|
-
AnthropicMessageCreateParams,
|
|
16
16
|
AnthropicToolResponse,
|
|
17
|
+
AnthropicMessageParam,
|
|
18
|
+
AnthropicTextBlockParam,
|
|
19
|
+
AnthropicImageBlockParam,
|
|
20
|
+
AnthropicToolUseBlockParam,
|
|
21
|
+
AnthropicMessageCreateParams,
|
|
22
|
+
AnthropicToolResultBlockParam,
|
|
17
23
|
} from '@/llm/anthropic/types';
|
|
18
24
|
|
|
19
25
|
function _formatImage(imageUrl: string): { type: string; media_type: string; data: string } {
|
|
@@ -130,7 +136,7 @@ function _formatContent(content: MessageContent): string | Record<string, any>[]
|
|
|
130
136
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
131
137
|
};
|
|
132
138
|
} else if (
|
|
133
|
-
textTypes.find((t) => t === contentPart.type) &&
|
|
139
|
+
textTypes.find((t) => t === contentPart.type) != null &&
|
|
134
140
|
'text' in contentPart
|
|
135
141
|
) {
|
|
136
142
|
// Assuming contentPart is of type MessageContentText here
|
|
@@ -139,7 +145,7 @@ function _formatContent(content: MessageContent): string | Record<string, any>[]
|
|
|
139
145
|
text: contentPart.text,
|
|
140
146
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
141
147
|
};
|
|
142
|
-
} else if (toolTypes.find((t) => t === contentPart.type)) {
|
|
148
|
+
} else if (toolTypes.find((t) => t === contentPart.type) != null) {
|
|
143
149
|
const contentPartCopy = { ...contentPart };
|
|
144
150
|
if ('index' in contentPartCopy) {
|
|
145
151
|
// Anthropic does not support passing the index field here, so we remove it.
|
|
@@ -252,7 +258,79 @@ export function _convertMessagesToAnthropicPayload(
|
|
|
252
258
|
}
|
|
253
259
|
});
|
|
254
260
|
return {
|
|
255
|
-
messages: formattedMessages,
|
|
261
|
+
messages: mergeMessages(formattedMessages as AnthropicMessageCreateParams['messages']),
|
|
256
262
|
system,
|
|
257
263
|
} as AnthropicMessageCreateParams;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function mergeMessages(messages?: AnthropicMessageCreateParams['messages']): AnthropicMessageParam[] {
|
|
267
|
+
if (!messages || messages.length <= 1) {
|
|
268
|
+
return messages ?? [];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const result: AnthropicMessageCreateParams['messages'] = [];
|
|
272
|
+
let currentMessage = messages[0];
|
|
273
|
+
|
|
274
|
+
const normalizeContent = (
|
|
275
|
+
content:
|
|
276
|
+
| string
|
|
277
|
+
| Array<
|
|
278
|
+
| AnthropicTextBlockParam
|
|
279
|
+
| AnthropicImageBlockParam
|
|
280
|
+
| AnthropicToolUseBlockParam
|
|
281
|
+
| AnthropicToolResultBlockParam
|
|
282
|
+
>
|
|
283
|
+
): Array<
|
|
284
|
+
| AnthropicTextBlockParam
|
|
285
|
+
| AnthropicImageBlockParam
|
|
286
|
+
| AnthropicToolUseBlockParam
|
|
287
|
+
| AnthropicToolResultBlockParam
|
|
288
|
+
> => {
|
|
289
|
+
if (typeof content === 'string') {
|
|
290
|
+
return [
|
|
291
|
+
{
|
|
292
|
+
type: 'text',
|
|
293
|
+
text: content,
|
|
294
|
+
},
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
return content;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const isToolResultMessage = (msg: (typeof messages)[0]): boolean => {
|
|
301
|
+
if (msg.role !== 'user') return false;
|
|
302
|
+
|
|
303
|
+
if (typeof msg.content === 'string') {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return (
|
|
308
|
+
Array.isArray(msg.content) &&
|
|
309
|
+
msg.content.every((item) => item.type === 'tool_result')
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
for (let i = 1; i < messages.length; i += 1) {
|
|
314
|
+
const nextMessage = messages[i];
|
|
315
|
+
|
|
316
|
+
if (
|
|
317
|
+
isToolResultMessage(currentMessage) &&
|
|
318
|
+
isToolResultMessage(nextMessage)
|
|
319
|
+
) {
|
|
320
|
+
// Merge the messages by combining their content arrays
|
|
321
|
+
currentMessage = {
|
|
322
|
+
...currentMessage,
|
|
323
|
+
content: [
|
|
324
|
+
...normalizeContent(currentMessage.content),
|
|
325
|
+
...normalizeContent(nextMessage.content),
|
|
326
|
+
],
|
|
327
|
+
};
|
|
328
|
+
} else {
|
|
329
|
+
result.push(currentMessage);
|
|
330
|
+
currentMessage = nextMessage;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
result.push(currentMessage);
|
|
335
|
+
return result;
|
|
258
336
|
}
|
package/src/llm/providers.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import { ChatOpenAI } from '@langchain/openai';
|
|
3
3
|
import { ChatOllama } from '@langchain/ollama';
|
|
4
4
|
import { ChatBedrockConverse } from '@langchain/aws';
|
|
5
|
-
import { ChatAnthropic } from '@langchain/anthropic';
|
|
5
|
+
// import { ChatAnthropic } from '@langchain/anthropic';
|
|
6
6
|
import { ChatMistralAI } from '@langchain/mistralai';
|
|
7
7
|
import { ChatVertexAI } from '@langchain/google-vertexai';
|
|
8
|
+
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
|
|
8
9
|
import { BedrockChat } from '@langchain/community/chat_models/bedrock/web';
|
|
9
10
|
import type { ChatModelConstructorMap, ProviderOptionsMap, ChatModelMap } from '@/types';
|
|
10
11
|
import { Providers } from '@/common';
|
|
11
|
-
|
|
12
|
+
import { CustomAnthropic } from '@/llm/anthropic/llm';
|
|
12
13
|
|
|
13
14
|
export const llmProviders: Partial<ChatModelConstructorMap> = {
|
|
14
15
|
[Providers.OPENAI]: ChatOpenAI,
|
|
@@ -17,8 +18,9 @@ export const llmProviders: Partial<ChatModelConstructorMap> = {
|
|
|
17
18
|
[Providers.BEDROCK_LEGACY]: BedrockChat,
|
|
18
19
|
[Providers.MISTRALAI]: ChatMistralAI,
|
|
19
20
|
[Providers.BEDROCK]: ChatBedrockConverse,
|
|
20
|
-
|
|
21
|
-
[Providers.ANTHROPIC]: ChatAnthropic,
|
|
21
|
+
[Providers.ANTHROPIC]: CustomAnthropic,
|
|
22
|
+
// [Providers.ANTHROPIC]: ChatAnthropic,
|
|
23
|
+
[Providers.GOOGLE]: ChatGoogleGenerativeAI,
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export const manualToolStreamProviders = new Set<Providers | string>([Providers.ANTHROPIC, Providers.BEDROCK, Providers.OLLAMA]);
|
package/src/llm/text.ts
CHANGED
|
@@ -1,73 +1,52 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import type { ReadableOptions } from 'stream';
|
|
4
|
-
export interface TextStreamOptions extends ReadableOptions {
|
|
2
|
+
export interface TextStreamOptions {
|
|
5
3
|
minChunkSize?: number;
|
|
6
4
|
maxChunkSize?: number;
|
|
7
5
|
delay?: number;
|
|
6
|
+
firstWordChunk?: boolean;
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
export type ProgressCallback = (chunk: string) => void;
|
|
11
10
|
export type PostChunkCallback = (chunk: string) => void;
|
|
12
11
|
|
|
13
|
-
export class TextStream
|
|
12
|
+
export class TextStream {
|
|
14
13
|
private text: string;
|
|
15
14
|
private currentIndex: number;
|
|
16
15
|
private minChunkSize: number;
|
|
17
16
|
private maxChunkSize: number;
|
|
18
17
|
private delay: number;
|
|
18
|
+
private firstWordChunk: boolean;
|
|
19
19
|
|
|
20
20
|
constructor(text: string, options: TextStreamOptions = {}) {
|
|
21
|
-
super(options);
|
|
22
21
|
this.text = text;
|
|
23
22
|
this.currentIndex = 0;
|
|
24
|
-
this.minChunkSize = options.minChunkSize ??
|
|
25
|
-
this.maxChunkSize = options.maxChunkSize ??
|
|
26
|
-
this.delay = options.delay ?? 20;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
_read(): void {
|
|
30
|
-
const { delay, minChunkSize, maxChunkSize } = this;
|
|
31
|
-
|
|
32
|
-
if (this.currentIndex < this.text.length) {
|
|
33
|
-
setTimeout(() => {
|
|
34
|
-
const remainingChars = this.text.length - this.currentIndex;
|
|
35
|
-
const chunkSize = Math.min(this.randomInt(minChunkSize, maxChunkSize + 1), remainingChars);
|
|
36
|
-
|
|
37
|
-
const chunk = this.text.slice(this.currentIndex, this.currentIndex + chunkSize);
|
|
38
|
-
this.push(chunk);
|
|
39
|
-
this.currentIndex += chunkSize;
|
|
40
|
-
}, delay);
|
|
41
|
-
} else {
|
|
42
|
-
this.push(null); // signal end of data
|
|
43
|
-
}
|
|
23
|
+
this.minChunkSize = options.minChunkSize ?? 4;
|
|
24
|
+
this.maxChunkSize = options.maxChunkSize ?? 8;
|
|
25
|
+
this.delay = options.delay ?? 20;
|
|
26
|
+
this.firstWordChunk = options.firstWordChunk ?? true;
|
|
44
27
|
}
|
|
45
28
|
|
|
46
29
|
private randomInt(min: number, max: number): number {
|
|
47
30
|
return Math.floor(Math.random() * (max - min)) + min;
|
|
48
31
|
}
|
|
49
32
|
|
|
50
|
-
|
|
51
|
-
const streamPromise = new Promise<void>((resolve, reject) => {
|
|
52
|
-
this.on('data', (chunk) => {
|
|
53
|
-
progressCallback(chunk.toString());
|
|
54
|
-
});
|
|
33
|
+
private static readonly BOUNDARIES = new Set([' ', '.', ',', '!', '?', ';', ':']);
|
|
55
34
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
});
|
|
35
|
+
private findFirstWordBoundary(text: string, minSize: number): number {
|
|
36
|
+
if (minSize >= text.length) return text.length;
|
|
59
37
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
});
|
|
63
|
-
});
|
|
38
|
+
// Ensure we meet the minimum size first
|
|
39
|
+
let pos = minSize;
|
|
64
40
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
41
|
+
// Look forward until we find a boundary
|
|
42
|
+
while (pos < text.length) {
|
|
43
|
+
if (TextStream.BOUNDARIES.has(text[pos])) {
|
|
44
|
+
return pos + 1; // Include the boundary character
|
|
45
|
+
}
|
|
46
|
+
pos++;
|
|
70
47
|
}
|
|
48
|
+
|
|
49
|
+
return text.length; // If no boundary found, return entire remaining text
|
|
71
50
|
}
|
|
72
51
|
|
|
73
52
|
async *generateText(progressCallback?: ProgressCallback): AsyncGenerator<string, void, unknown> {
|
|
@@ -76,11 +55,17 @@ export class TextStream extends Readable {
|
|
|
76
55
|
while (this.currentIndex < this.text.length) {
|
|
77
56
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
78
57
|
|
|
79
|
-
const
|
|
80
|
-
|
|
58
|
+
const remainingText = this.text.slice(this.currentIndex);
|
|
59
|
+
let chunkSize: number;
|
|
81
60
|
|
|
82
|
-
|
|
61
|
+
if (this.firstWordChunk) {
|
|
62
|
+
chunkSize = this.findFirstWordBoundary(remainingText, minChunkSize);
|
|
63
|
+
} else {
|
|
64
|
+
const remainingChars = remainingText.length;
|
|
65
|
+
chunkSize = Math.min(this.randomInt(minChunkSize, maxChunkSize + 1), remainingChars);
|
|
66
|
+
}
|
|
83
67
|
|
|
68
|
+
const chunk = this.text.slice(this.currentIndex, this.currentIndex + chunkSize);
|
|
84
69
|
progressCallback?.(chunk);
|
|
85
70
|
|
|
86
71
|
yield chunk;
|
package/src/messages.ts
CHANGED
|
@@ -33,7 +33,7 @@ User: ${userMessage[1]}
|
|
|
33
33
|
|
|
34
34
|
const modifyContent = (messageType: string, content: t.ExtendedMessageContent[]): t.ExtendedMessageContent[] => {
|
|
35
35
|
return content.map(item => {
|
|
36
|
-
if (item && typeof item === 'object' && 'type' in item && item.type) {
|
|
36
|
+
if (item && typeof item === 'object' && 'type' in item && item.type != null && item.type) {
|
|
37
37
|
let newType = item.type;
|
|
38
38
|
if (newType.endsWith('_delta')) {
|
|
39
39
|
newType = newType.replace('_delta', '');
|
|
@@ -80,9 +80,9 @@ export function formatAnthropicMessage(message: AIMessageChunk): AIMessage {
|
|
|
80
80
|
formattedContent = message.content.reduce<t.ExtendedMessageContent[]>((acc, item) => {
|
|
81
81
|
if (typeof item === 'object' && item !== null) {
|
|
82
82
|
const extendedItem = item as t.ExtendedMessageContent;
|
|
83
|
-
if (extendedItem.type === 'text' && extendedItem.text) {
|
|
83
|
+
if (extendedItem.type === 'text' && extendedItem.text != null && extendedItem.text) {
|
|
84
84
|
acc.push({ type: 'text', text: extendedItem.text });
|
|
85
|
-
} else if (extendedItem.type === 'tool_use' && extendedItem.id) {
|
|
85
|
+
} else if (extendedItem.type === 'tool_use' && extendedItem.id != null && extendedItem.id) {
|
|
86
86
|
const toolCall = toolCallMap.get(extendedItem.id);
|
|
87
87
|
if (toolCall) {
|
|
88
88
|
acc.push({
|
|
@@ -92,7 +92,7 @@ export function formatAnthropicMessage(message: AIMessageChunk): AIMessage {
|
|
|
92
92
|
input: toolCall.args as unknown as string
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
-
} else if ('input' in extendedItem && extendedItem.input) {
|
|
95
|
+
} else if ('input' in extendedItem && extendedItem.input != null && extendedItem.input) {
|
|
96
96
|
try {
|
|
97
97
|
const parsedInput = JSON.parse(extendedItem.input);
|
|
98
98
|
const toolCall = message.tool_calls?.find(tc => tc.args.input === parsedInput.input);
|
|
@@ -210,14 +210,14 @@ export function convertMessagesToContent(messages: BaseMessage[]): t.MessageCont
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
export function formatAnthropicArtifactContent(messages: BaseMessage[]): void {
|
|
213
|
-
const
|
|
214
|
-
if (!(
|
|
213
|
+
const lastMessage = messages[messages.length - 1];
|
|
214
|
+
if (!(lastMessage instanceof ToolMessage)) return;
|
|
215
215
|
|
|
216
216
|
// Find the latest AIMessage with tool_calls that this tool message belongs to
|
|
217
217
|
const latestAIParentIndex = findLastIndex(messages,
|
|
218
218
|
msg => (msg instanceof AIMessageChunk &&
|
|
219
219
|
(msg.tool_calls?.length ?? 0) > 0 &&
|
|
220
|
-
msg.tool_calls?.some(tc => tc.id ===
|
|
220
|
+
msg.tool_calls?.some(tc => tc.id === lastMessage.tool_call_id)) ?? false
|
|
221
221
|
);
|
|
222
222
|
|
|
223
223
|
if (latestAIParentIndex === -1) return;
|
|
@@ -233,70 +233,19 @@ export function formatAnthropicArtifactContent(messages: BaseMessage[]): void {
|
|
|
233
233
|
|
|
234
234
|
if (!hasArtifactContent) return;
|
|
235
235
|
|
|
236
|
-
// Now we know we need to process these messages
|
|
237
236
|
const message = messages[latestAIParentIndex] as AIMessageChunk;
|
|
238
237
|
const toolCallIds = message.tool_calls?.map(tc => tc.id) ?? [];
|
|
239
|
-
const toolMessages: ToolMessage[] = [];
|
|
240
|
-
let lastToolIndex = latestAIParentIndex;
|
|
241
238
|
|
|
242
|
-
// Collect all corresponding ToolMessages
|
|
243
239
|
for (let j = latestAIParentIndex + 1; j < messages.length; j++) {
|
|
244
|
-
const
|
|
245
|
-
if (
|
|
246
|
-
toolCallIds.includes(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
Array.isArray(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (hasContentArtifacts) {
|
|
253
|
-
potentialToolMessage.content = potentialToolMessage.content.concat(potentialToolMessage.artifact?.content);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
toolMessages.push(potentialToolMessage);
|
|
257
|
-
lastToolIndex = Math.max(lastToolIndex, j);
|
|
240
|
+
const msg = messages[j];
|
|
241
|
+
if (msg instanceof ToolMessage &&
|
|
242
|
+
toolCallIds.includes(msg.tool_call_id) &&
|
|
243
|
+
msg.artifact != null &&
|
|
244
|
+
Array.isArray(msg.artifact?.content) &&
|
|
245
|
+
Array.isArray(msg.content)) {
|
|
246
|
+
msg.content = msg.content.concat(msg.artifact.content);
|
|
258
247
|
}
|
|
259
248
|
}
|
|
260
|
-
|
|
261
|
-
// Rest of the function remains the same...
|
|
262
|
-
if (toolMessages.length > 1) {
|
|
263
|
-
// Keep only first tool call in original AI message
|
|
264
|
-
const originalContent = Array.isArray(message.content) ? message.content : [];
|
|
265
|
-
message.content = [
|
|
266
|
-
originalContent.find(c => c.type === 'text'),
|
|
267
|
-
originalContent.find(c => c.type === 'tool_use' && c.id === toolCallIds[0])
|
|
268
|
-
].filter(Boolean) as t.ExtendedMessageContent[];
|
|
269
|
-
|
|
270
|
-
message.tool_calls = [message.tool_calls![0]];
|
|
271
|
-
if (message.tool_call_chunks) {
|
|
272
|
-
message.tool_call_chunks = [message.tool_call_chunks[0]];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const newMessages: BaseMessage[] = [];
|
|
276
|
-
newMessages.push(toolMessages[0]);
|
|
277
|
-
|
|
278
|
-
// Create new AI+Tool message pairs for remaining tool calls
|
|
279
|
-
for (let k = 1; k < toolMessages.length; k++) {
|
|
280
|
-
const relevantToolCall = message.lc_kwargs.tool_calls[k];
|
|
281
|
-
const relevantToolChunk = message.lc_kwargs.tool_call_chunks?.[k];
|
|
282
|
-
const relevantToolUse = originalContent.find(c =>
|
|
283
|
-
c.type === 'tool_use' && c.id === toolCallIds[k]
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
const newAIMessage = new AIMessage({
|
|
287
|
-
content: [
|
|
288
|
-
originalContent.find(c => c.type === 'text'),
|
|
289
|
-
relevantToolUse
|
|
290
|
-
].filter(Boolean),
|
|
291
|
-
tool_calls: [relevantToolCall],
|
|
292
|
-
tool_call_chunks: relevantToolChunk != null ? [relevantToolChunk] : undefined,
|
|
293
|
-
additional_kwargs: { ...message.additional_kwargs }
|
|
294
|
-
} as AIMessageChunk);
|
|
295
|
-
newMessages.push(newAIMessage, toolMessages[k]);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
messages.splice(latestAIParentIndex + 1, lastToolIndex - latestAIParentIndex , ...newMessages);
|
|
299
|
-
}
|
|
300
249
|
}
|
|
301
250
|
|
|
302
251
|
export function formatOpenAIArtifactContent(messages: BaseMessage[]): void {
|
package/src/scripts/args.ts
CHANGED
|
@@ -20,7 +20,7 @@ export async function getArgs(): Promise<{ userName: string; location: string; p
|
|
|
20
20
|
alias: 'p',
|
|
21
21
|
type: 'string',
|
|
22
22
|
description: 'LLM provider',
|
|
23
|
-
choices: ['openAI', 'anthropic', 'mistralai', 'vertexai', 'bedrock', 'ollama'],
|
|
23
|
+
choices: ['openAI', 'anthropic', 'mistralai', 'vertexai', 'bedrock', 'ollama', 'google'],
|
|
24
24
|
default: 'openAI'
|
|
25
25
|
})
|
|
26
26
|
.help()
|
package/src/scripts/code_exec.ts
CHANGED
|
@@ -171,6 +171,10 @@ process.on('unhandledRejection', (reason, promise) => {
|
|
|
171
171
|
process.exit(1);
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
+
process.on('uncaughtException', (err) => {
|
|
175
|
+
console.error('Uncaught Exception:', err);
|
|
176
|
+
});
|
|
177
|
+
|
|
174
178
|
testCodeExecution().catch((err) => {
|
|
175
179
|
console.error(err);
|
|
176
180
|
console.log('Conversation history:');
|
package/src/scripts/simple.ts
CHANGED
|
@@ -117,6 +117,10 @@ process.on('unhandledRejection', (reason, promise) => {
|
|
|
117
117
|
process.exit(1);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
process.on('uncaughtException', (err) => {
|
|
121
|
+
console.error('Uncaught Exception:', err);
|
|
122
|
+
});
|
|
123
|
+
|
|
120
124
|
testStandardStreaming().catch((err) => {
|
|
121
125
|
console.error(err);
|
|
122
126
|
console.log('Conversation history:');
|