@librechat/agents 1.4.4 → 1.4.6
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/graphs/Graph.cjs +4 -0
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/messages.cjs +2 -2
- package/dist/cjs/messages.cjs.map +1 -1
- package/dist/cjs/run.cjs +5 -1
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +50 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +4 -0
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/messages.mjs +2 -2
- package/dist/esm/messages.mjs.map +1 -1
- package/dist/esm/run.mjs +5 -1
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +50 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +5 -2
- package/dist/types/messages.d.ts +1 -1
- package/dist/types/run.d.ts +1 -0
- package/dist/types/scripts/tools.d.ts +1 -0
- package/dist/types/types/run.d.ts +1 -0
- package/dist/types/types/stream.d.ts +10 -1
- package/package.json +2 -1
- package/src/graphs/Graph.ts +6 -2
- package/src/messages.ts +5 -5
- package/src/run.ts +6 -1
- package/src/scripts/content.ts +3 -2
- package/src/scripts/tools.ts +120 -0
- package/src/stream.ts +53 -4
- package/src/types/run.ts +1 -0
- package/src/types/stream.ts +7 -1
package/src/messages.ts
CHANGED
|
@@ -9,7 +9,7 @@ export function getConverseOverrideMessage({
|
|
|
9
9
|
lastMessageY
|
|
10
10
|
}: {
|
|
11
11
|
userMessage: string[];
|
|
12
|
-
lastMessageX: AIMessageChunk;
|
|
12
|
+
lastMessageX: AIMessageChunk | null;
|
|
13
13
|
lastMessageY: ToolMessage;
|
|
14
14
|
}): HumanMessage {
|
|
15
15
|
const content = `
|
|
@@ -19,7 +19,7 @@ User: ${userMessage[1]}
|
|
|
19
19
|
# YOU HAVE ALREADY RESPONDED TO THE LATEST USER MESSAGE:
|
|
20
20
|
|
|
21
21
|
# Observations:
|
|
22
|
-
- ${lastMessageX
|
|
22
|
+
- ${lastMessageX?.content}
|
|
23
23
|
|
|
24
24
|
# Tool Calls:
|
|
25
25
|
- ${lastMessageX?.tool_calls?.join('\n- ')}
|
|
@@ -149,8 +149,8 @@ export function formatAnthropicMessage(message: AIMessageChunk): AIMessage {
|
|
|
149
149
|
export function convertMessagesToContent(messages: BaseMessage[]): t.MessageContentComplex[] {
|
|
150
150
|
const processedContent: t.MessageContentComplex[] = [];
|
|
151
151
|
|
|
152
|
-
const addContentPart = (message: BaseMessage): void => {
|
|
153
|
-
const content = message?.content;
|
|
152
|
+
const addContentPart = (message: BaseMessage | null): void => {
|
|
153
|
+
const content = message?.lc_kwargs.content != null ? message.lc_kwargs.content : message?.content;
|
|
154
154
|
if (content === undefined) {
|
|
155
155
|
return;
|
|
156
156
|
}
|
|
@@ -169,7 +169,7 @@ export function convertMessagesToContent(messages: BaseMessage[]): t.MessageCont
|
|
|
169
169
|
const toolCallMap = new Map<string, t.CustomToolCall>();
|
|
170
170
|
|
|
171
171
|
for (let i = 0; i < messages.length; i++) {
|
|
172
|
-
const message = messages[i];
|
|
172
|
+
const message = messages[i] as BaseMessage | null;
|
|
173
173
|
const messageType = message?._getType();
|
|
174
174
|
|
|
175
175
|
if (messageType === 'ai' && (message as AIMessage).tool_calls?.length) {
|
package/src/run.ts
CHANGED
|
@@ -16,6 +16,7 @@ export class Run<T extends t.BaseGraphState> {
|
|
|
16
16
|
private Graph: StandardGraph | undefined;
|
|
17
17
|
provider: Providers | undefined;
|
|
18
18
|
run_id: string | undefined;
|
|
19
|
+
returnContent: boolean = false;
|
|
19
20
|
|
|
20
21
|
private constructor(config: t.RunConfig) {
|
|
21
22
|
const handlerRegistry = new HandlerRegistry();
|
|
@@ -35,6 +36,8 @@ export class Run<T extends t.BaseGraphState> {
|
|
|
35
36
|
this.Graph.handlerRegistry = handlerRegistry;
|
|
36
37
|
}
|
|
37
38
|
}
|
|
39
|
+
|
|
40
|
+
this.returnContent = config.returnContent ?? false;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
private createStandardGraph(config: t.StandardGraphConfig): t.CompiledWorkflow<t.IState, Partial<t.IState>, string> {
|
|
@@ -108,7 +111,9 @@ export class Run<T extends t.BaseGraphState> {
|
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
if (this.returnContent) {
|
|
115
|
+
return this.Graph.getContentParts();
|
|
116
|
+
}
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
private createSystemCallback<K extends keyof ClientCallbacks>(
|
package/src/scripts/content.ts
CHANGED
|
@@ -68,6 +68,7 @@ async function testStandardStreaming(): Promise<void> {
|
|
|
68
68
|
instructions: 'You are a friendly AI assistant. Always address the user by their name.',
|
|
69
69
|
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
70
70
|
},
|
|
71
|
+
returnContent: true,
|
|
71
72
|
customHandlers,
|
|
72
73
|
});
|
|
73
74
|
|
|
@@ -99,9 +100,9 @@ async function testStandardStreaming(): Promise<void> {
|
|
|
99
100
|
conversationHistory.push(...finalMessages);
|
|
100
101
|
console.dir(conversationHistory, { depth: null });
|
|
101
102
|
}
|
|
102
|
-
console.dir(finalContentParts, { depth: null });
|
|
103
|
+
// console.dir(finalContentParts, { depth: null });
|
|
103
104
|
console.log('\n\n====================\n\n');
|
|
104
|
-
console.dir(contentParts, { depth: null });
|
|
105
|
+
// console.dir(contentParts, { depth: null });
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
process.on('unhandledRejection', (reason, promise) => {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
// src/scripts/cli.ts
|
|
3
|
+
import { config } from 'dotenv';
|
|
4
|
+
config();
|
|
5
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
6
|
+
import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
|
|
7
|
+
import type * as t from '@/types';
|
|
8
|
+
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
9
|
+
import { ToolEndHandler } from '@/events';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
import { getArgs } from '@/scripts/args';
|
|
13
|
+
import { Run } from '@/run';
|
|
14
|
+
import { GraphEvents, Callback } from '@/common';
|
|
15
|
+
import { getLLMConfig } from '@/utils/llmConfig';
|
|
16
|
+
|
|
17
|
+
const conversationHistory: BaseMessage[] = [];
|
|
18
|
+
async function testStandardStreaming(): Promise<void> {
|
|
19
|
+
const { userName, location, provider, currentDate } = await getArgs();
|
|
20
|
+
const { contentParts, aggregateContent } = createContentAggregator();
|
|
21
|
+
const customHandlers = {
|
|
22
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
23
|
+
// [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
24
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
25
|
+
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
26
|
+
handle: (event: GraphEvents.ON_RUN_STEP_COMPLETED, data: t.StreamEventData): void => {
|
|
27
|
+
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
28
|
+
// console.dir(data, { depth: null });
|
|
29
|
+
aggregateContent({ event, data: data as unknown as { result: t.ToolEndEvent } });
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
33
|
+
handle: (event: GraphEvents.ON_RUN_STEP, data: t.StreamEventData): void => {
|
|
34
|
+
console.log('====== ON_RUN_STEP ======');
|
|
35
|
+
console.dir(data, { depth: null });
|
|
36
|
+
aggregateContent({ event, data: data as t.RunStep });
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
40
|
+
handle: (event: GraphEvents.ON_RUN_STEP_DELTA, data: t.StreamEventData): void => {
|
|
41
|
+
console.log('====== ON_RUN_STEP_DELTA ======');
|
|
42
|
+
console.dir(data, { depth: null });
|
|
43
|
+
aggregateContent({ event, data: data as t.RunStepDeltaEvent });
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
47
|
+
handle: (event: GraphEvents.ON_MESSAGE_DELTA, data: t.StreamEventData): void => {
|
|
48
|
+
console.log('====== ON_MESSAGE_DELTA ======');
|
|
49
|
+
console.dir(data, { depth: null });
|
|
50
|
+
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
[GraphEvents.TOOL_START]: {
|
|
54
|
+
handle: (_event: string, data: t.StreamEventData, metadata?: Record<string, unknown>): void => {
|
|
55
|
+
console.log('====== TOOL_START ======');
|
|
56
|
+
// console.dir(data, { depth: null });
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const llmConfig = getLLMConfig(provider);
|
|
62
|
+
|
|
63
|
+
const run = await Run.create<t.IState>({
|
|
64
|
+
graphConfig: {
|
|
65
|
+
type: 'standard',
|
|
66
|
+
llmConfig,
|
|
67
|
+
tools: [new TavilySearchResults()],
|
|
68
|
+
instructions: 'You are a friendly AI assistant. Always address the user by their name.',
|
|
69
|
+
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
70
|
+
},
|
|
71
|
+
returnContent: true,
|
|
72
|
+
customHandlers,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const config = {
|
|
76
|
+
configurable: {
|
|
77
|
+
provider,
|
|
78
|
+
thread_id: 'conversation-num-1',
|
|
79
|
+
},
|
|
80
|
+
streamMode: 'values',
|
|
81
|
+
version: 'v2' as const,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
console.log('Test 1: Weather query (content parts test)');
|
|
85
|
+
|
|
86
|
+
const userMessage = `
|
|
87
|
+
Make a search for the weather in ${location} today, which is ${currentDate}.
|
|
88
|
+
Before making the search, please let me know what you're about to do, then immediately start searching without hesitation.
|
|
89
|
+
Make sure to always refer to me by name, which is ${userName}.
|
|
90
|
+
After giving me a thorough summary, tell me a joke about the weather forecast we went over.
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
conversationHistory.push(new HumanMessage(userMessage));
|
|
94
|
+
|
|
95
|
+
const inputs = {
|
|
96
|
+
messages: conversationHistory,
|
|
97
|
+
};
|
|
98
|
+
const finalContentParts = await run.processStream(inputs, config);
|
|
99
|
+
const finalMessages = run.getRunMessages();
|
|
100
|
+
if (finalMessages) {
|
|
101
|
+
conversationHistory.push(...finalMessages);
|
|
102
|
+
console.dir(conversationHistory, { depth: null });
|
|
103
|
+
}
|
|
104
|
+
// console.dir(finalContentParts, { depth: null });
|
|
105
|
+
console.log('\n\n====================\n\n');
|
|
106
|
+
// console.dir(contentParts, { depth: null });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
110
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
111
|
+
console.log('Conversation history:');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
testStandardStreaming().catch((err) => {
|
|
116
|
+
console.error(err);
|
|
117
|
+
console.log('Conversation history:');
|
|
118
|
+
console.dir(conversationHistory, { depth: null });
|
|
119
|
+
process.exit(1);
|
|
120
|
+
});
|
package/src/stream.ts
CHANGED
|
@@ -56,15 +56,51 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
56
56
|
|
|
57
57
|
if (hasToolCalls && chunk.tool_calls?.every((tc) => tc.id)) {
|
|
58
58
|
const tool_calls: ToolCall[] = [];
|
|
59
|
+
const tool_call_ids: string[] = [];
|
|
59
60
|
for (const tool_call of chunk.tool_calls) {
|
|
60
|
-
|
|
61
|
+
const toolCallId = tool_call.id ?? '';
|
|
62
|
+
if (!toolCallId || graph.toolCallStepIds.has(toolCallId)) {
|
|
61
63
|
continue;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
tool_calls.push(tool_call);
|
|
67
|
+
tool_call_ids.push(toolCallId);
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
const stepKey = graph.getStepKey(metadata);
|
|
71
|
+
|
|
72
|
+
let prevStepId = '';
|
|
73
|
+
let prevRunStep: t.RunStep | undefined;
|
|
74
|
+
try {
|
|
75
|
+
prevStepId = graph.getStepIdByKey(stepKey, graph.contentData.length - 1);
|
|
76
|
+
prevRunStep = graph.getRunStep(prevStepId);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
// no previous step
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const dispatchToolCallIds = (lastMessageStepId: string): void => {
|
|
82
|
+
graph.dispatchMessageDelta(lastMessageStepId, {
|
|
83
|
+
content: [{
|
|
84
|
+
type: 'text',
|
|
85
|
+
text: '',
|
|
86
|
+
tool_call_ids,
|
|
87
|
+
}],
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
/* If the previous step exists and is a message creation */
|
|
91
|
+
if (prevStepId && prevRunStep && prevRunStep.type === StepTypes.MESSAGE_CREATION) {
|
|
92
|
+
dispatchToolCallIds(prevStepId);
|
|
93
|
+
/* If the previous step doesn't exist or is not a message creation */
|
|
94
|
+
} else if (!prevRunStep || prevRunStep.type !== StepTypes.MESSAGE_CREATION) {
|
|
95
|
+
const messageId = getMessageId(stepKey, graph) ?? '';
|
|
96
|
+
const stepId = graph.dispatchRunStep(stepKey, {
|
|
97
|
+
type: StepTypes.MESSAGE_CREATION,
|
|
98
|
+
message_creation: {
|
|
99
|
+
message_id: messageId,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
dispatchToolCallIds(stepId);
|
|
103
|
+
}
|
|
68
104
|
graph.dispatchRunStep(stepKey, {
|
|
69
105
|
type: StepTypes.TOOL_CALLS,
|
|
70
106
|
tool_calls,
|
|
@@ -90,7 +126,9 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
90
126
|
const stepKey = graph.getStepKey(metadata);
|
|
91
127
|
|
|
92
128
|
if (hasToolCallChunks && chunk.tool_call_chunks?.length && typeof chunk.tool_call_chunks[0]?.index === 'number') {
|
|
93
|
-
const
|
|
129
|
+
const prevStepId = graph.getStepIdByKey(stepKey, graph.contentData.length - 1);
|
|
130
|
+
const prevRunStep = graph.getRunStep(prevStepId);
|
|
131
|
+
const stepId = graph.getStepIdByKey(stepKey, prevRunStep?.index);
|
|
94
132
|
graph.dispatchRunStepDelta(stepId, {
|
|
95
133
|
type: StepTypes.TOOL_CALLS,
|
|
96
134
|
tool_calls: chunk.tool_call_chunks,
|
|
@@ -183,16 +221,27 @@ export function createContentAggregator(): ContentAggregatorResult {
|
|
|
183
221
|
contentParts[index] = { type: partType };
|
|
184
222
|
}
|
|
185
223
|
|
|
224
|
+
if (contentPart.type !== contentParts[index]?.type) {
|
|
225
|
+
console.warn('Content type mismatch');
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
186
229
|
if (
|
|
187
230
|
partType.startsWith(ContentTypes.TEXT) &&
|
|
188
231
|
ContentTypes.TEXT in contentPart &&
|
|
189
232
|
typeof contentPart.text === 'string'
|
|
190
233
|
) {
|
|
191
|
-
|
|
192
|
-
contentParts[index]
|
|
234
|
+
// TODO: update this!!
|
|
235
|
+
const currentContent = contentParts[index] as t.MessageDeltaUpdate;
|
|
236
|
+
const update: t.MessageDeltaUpdate = {
|
|
193
237
|
type: ContentTypes.TEXT,
|
|
194
238
|
text: (currentContent.text || '') + contentPart.text,
|
|
195
239
|
};
|
|
240
|
+
|
|
241
|
+
if (contentPart.tool_call_ids) {
|
|
242
|
+
update.tool_call_ids = contentPart.tool_call_ids;
|
|
243
|
+
}
|
|
244
|
+
contentParts[index] = update;
|
|
196
245
|
} else if (partType === ContentTypes.IMAGE_URL && 'image_url' in contentPart) {
|
|
197
246
|
const currentContent = contentParts[index] as { type: 'image_url'; image_url: string };
|
|
198
247
|
contentParts[index] = {
|
package/src/types/run.ts
CHANGED
package/src/types/stream.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/types/stream.ts
|
|
2
2
|
import type { MessageContentImageUrl, MessageContentText, ToolMessage } from '@langchain/core/messages';
|
|
3
3
|
import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
|
|
4
|
-
import { StepTypes } from '@/common/enum';
|
|
4
|
+
import { StepTypes, ContentTypes } from '@/common/enum';
|
|
5
5
|
|
|
6
6
|
/** Event names are of the format: on_[runnable_type]_(start|stream|end).
|
|
7
7
|
|
|
@@ -158,8 +158,14 @@ export interface MessageDelta {
|
|
|
158
158
|
* The content of the message in array of text and/or images.
|
|
159
159
|
*/
|
|
160
160
|
content?: MessageContentComplex[];
|
|
161
|
+
/**
|
|
162
|
+
* The tool call ids associated with the message.
|
|
163
|
+
*/
|
|
164
|
+
tool_call_ids?: string[];
|
|
161
165
|
}
|
|
162
166
|
|
|
167
|
+
export type MessageDeltaUpdate = { type: ContentTypes.TEXT; text: string; tool_call_ids?: string[] };
|
|
168
|
+
|
|
163
169
|
export type ContentType = 'text' | 'image_url' | 'tool_call' | string;
|
|
164
170
|
|
|
165
171
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|