@librechat/agents 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/common/enum.cjs +108 -0
  3. package/dist/cjs/common/enum.cjs.map +1 -0
  4. package/dist/cjs/events.cjs +104 -0
  5. package/dist/cjs/events.cjs.map +1 -0
  6. package/dist/cjs/graphs/Graph.cjs +313 -0
  7. package/dist/cjs/graphs/Graph.cjs.map +1 -0
  8. package/dist/cjs/llm/providers.cjs +30 -0
  9. package/dist/cjs/llm/providers.cjs.map +1 -0
  10. package/dist/cjs/main.cjs +59 -0
  11. package/dist/cjs/main.cjs.map +1 -0
  12. package/dist/cjs/messages.cjs +195 -0
  13. package/dist/cjs/messages.cjs.map +1 -0
  14. package/dist/cjs/run.cjs +106 -0
  15. package/dist/cjs/run.cjs.map +1 -0
  16. package/dist/cjs/stream.cjs +133 -0
  17. package/dist/cjs/stream.cjs.map +1 -0
  18. package/dist/cjs/tools/ToolNode.cjs +80 -0
  19. package/dist/cjs/tools/ToolNode.cjs.map +1 -0
  20. package/dist/cjs/utils/graph.cjs +16 -0
  21. package/dist/cjs/utils/graph.cjs.map +1 -0
  22. package/dist/cjs/utils/run.cjs +59 -0
  23. package/dist/cjs/utils/run.cjs.map +1 -0
  24. package/dist/esm/common/enum.mjs +108 -0
  25. package/dist/esm/common/enum.mjs.map +1 -0
  26. package/dist/esm/events.mjs +97 -0
  27. package/dist/esm/events.mjs.map +1 -0
  28. package/dist/esm/graphs/Graph.mjs +310 -0
  29. package/dist/esm/graphs/Graph.mjs.map +1 -0
  30. package/dist/esm/llm/providers.mjs +27 -0
  31. package/dist/esm/llm/providers.mjs.map +1 -0
  32. package/dist/esm/main.mjs +9 -0
  33. package/dist/esm/main.mjs.map +1 -0
  34. package/dist/esm/messages.mjs +190 -0
  35. package/dist/esm/messages.mjs.map +1 -0
  36. package/dist/esm/run.mjs +104 -0
  37. package/dist/esm/run.mjs.map +1 -0
  38. package/dist/esm/stream.mjs +131 -0
  39. package/dist/esm/stream.mjs.map +1 -0
  40. package/dist/esm/tools/ToolNode.mjs +77 -0
  41. package/dist/esm/tools/ToolNode.mjs.map +1 -0
  42. package/dist/esm/utils/graph.mjs +13 -0
  43. package/dist/esm/utils/graph.mjs.map +1 -0
  44. package/dist/esm/utils/run.mjs +57 -0
  45. package/dist/esm/utils/run.mjs.map +1 -0
  46. package/dist/types/common/enum.d.ts +79 -0
  47. package/dist/types/common/index.d.ts +1 -0
  48. package/dist/types/events.d.ts +22 -0
  49. package/dist/types/graphs/Graph.d.ts +86 -0
  50. package/dist/types/graphs/index.d.ts +1 -0
  51. package/dist/types/index.d.ts +8 -0
  52. package/dist/types/llm/providers.d.ts +4 -0
  53. package/dist/types/messages.d.ts +10 -0
  54. package/dist/types/prompts/collab.d.ts +1 -0
  55. package/dist/types/prompts/index.d.ts +2 -0
  56. package/dist/types/prompts/taskmanager.d.ts +41 -0
  57. package/dist/types/run.d.ts +21 -0
  58. package/dist/types/scripts/args.d.ts +6 -0
  59. package/dist/types/scripts/cli.d.ts +1 -0
  60. package/dist/types/scripts/cli2.d.ts +1 -0
  61. package/dist/types/scripts/cli3.d.ts +1 -0
  62. package/dist/types/scripts/cli4.d.ts +1 -0
  63. package/dist/types/scripts/cli5.d.ts +1 -0
  64. package/dist/types/scripts/empty_input.d.ts +1 -0
  65. package/dist/types/stream.d.ts +5 -0
  66. package/dist/types/tools/ToolNode.d.ts +15 -0
  67. package/dist/types/tools/example.d.ts +26 -0
  68. package/dist/types/types/graph.d.ts +108 -0
  69. package/dist/types/types/index.d.ts +5 -0
  70. package/dist/types/types/llm.d.ts +25 -0
  71. package/dist/types/types/run.d.ts +53 -0
  72. package/dist/types/types/stream.d.ts +134 -0
  73. package/dist/types/types/tools.d.ts +24 -0
  74. package/dist/types/utils/graph.d.ts +2 -0
  75. package/dist/types/utils/index.d.ts +2 -0
  76. package/dist/types/utils/llmConfig.d.ts +2 -0
  77. package/dist/types/utils/logging.d.ts +1 -0
  78. package/dist/types/utils/run.d.ts +20 -0
  79. package/package.json +142 -0
  80. package/src/common/enum.ts +121 -0
  81. package/src/common/index.ts +2 -0
  82. package/src/events.ts +110 -0
  83. package/src/graphs/Graph.ts +416 -0
  84. package/src/graphs/index.ts +1 -0
  85. package/src/index.ts +15 -0
  86. package/src/llm/providers.ts +27 -0
  87. package/src/messages.ts +210 -0
  88. package/src/prompts/collab.ts +6 -0
  89. package/src/prompts/index.ts +2 -0
  90. package/src/prompts/taskmanager.ts +61 -0
  91. package/src/proto/CollabGraph.ts +269 -0
  92. package/src/proto/TaskManager.ts +243 -0
  93. package/src/proto/collab.ts +200 -0
  94. package/src/proto/collab_design.ts +184 -0
  95. package/src/proto/collab_design_v2.ts +224 -0
  96. package/src/proto/collab_design_v3.ts +255 -0
  97. package/src/proto/collab_design_v4.ts +220 -0
  98. package/src/proto/collab_design_v5.ts +251 -0
  99. package/src/proto/collab_graph.ts +181 -0
  100. package/src/proto/collab_original.ts +123 -0
  101. package/src/proto/example.ts +93 -0
  102. package/src/proto/example_new.ts +68 -0
  103. package/src/proto/example_old.ts +201 -0
  104. package/src/proto/example_test.ts +152 -0
  105. package/src/proto/example_test_anthropic.ts +100 -0
  106. package/src/proto/log_stream.ts +202 -0
  107. package/src/proto/main_collab_community_event.ts +133 -0
  108. package/src/proto/main_collab_design_v2.ts +96 -0
  109. package/src/proto/main_collab_design_v4.ts +100 -0
  110. package/src/proto/main_collab_design_v5.ts +135 -0
  111. package/src/proto/main_collab_global_analysis.ts +122 -0
  112. package/src/proto/main_collab_hackathon_event.ts +153 -0
  113. package/src/proto/main_collab_space_mission.ts +153 -0
  114. package/src/proto/main_philosophy.ts +210 -0
  115. package/src/proto/original_script.ts +126 -0
  116. package/src/proto/standard.ts +100 -0
  117. package/src/proto/stream.ts +56 -0
  118. package/src/proto/tasks.ts +118 -0
  119. package/src/proto/tools/global_analysis_tools.ts +86 -0
  120. package/src/proto/tools/space_mission_tools.ts +60 -0
  121. package/src/proto/vertexai.ts +54 -0
  122. package/src/run.ts +132 -0
  123. package/src/scripts/args.ts +42 -0
  124. package/src/scripts/cli.ts +166 -0
  125. package/src/scripts/cli2.ts +124 -0
  126. package/src/scripts/cli3.ts +175 -0
  127. package/src/scripts/cli4.ts +182 -0
  128. package/src/scripts/cli5.ts +182 -0
  129. package/src/scripts/empty_input.ts +136 -0
  130. package/src/stream.ts +145 -0
  131. package/src/tools/ToolNode.ts +108 -0
  132. package/src/tools/example.ts +52 -0
  133. package/src/types/graph.ts +126 -0
  134. package/src/types/index.ts +6 -0
  135. package/src/types/llm.ts +38 -0
  136. package/src/types/run.ts +56 -0
  137. package/src/types/stream.ts +174 -0
  138. package/src/types/tools.ts +31 -0
  139. package/src/utils/graph.ts +11 -0
  140. package/src/utils/index.ts +2 -0
  141. package/src/utils/llmConfig.ts +50 -0
  142. package/src/utils/logging.ts +48 -0
  143. package/src/utils/run.ts +91 -0
@@ -0,0 +1,416 @@
1
+ // src/graphs/Graph.ts
2
+ import { nanoid } from 'nanoid';
3
+ import { concat } from '@langchain/core/utils/stream';
4
+ import { ToolNode } from '@langchain/langgraph/prebuilt';
5
+ import { START, StateGraph } from '@langchain/langgraph';
6
+ import { Runnable, RunnableConfig } from '@langchain/core/runnables';
7
+ import { dispatchCustomEvent } from '@langchain/core/callbacks/dispatch';
8
+ import { AIMessageChunk, ToolMessage, SystemMessage } from '@langchain/core/messages';
9
+ import type { BaseMessage } from '@langchain/core/messages';
10
+ import type { StructuredTool } from '@langchain/core/tools';
11
+ import type * as t from '@/types';
12
+ import { Providers, GraphEvents, GraphNodeKeys, StepTypes, Callback } from '@/common';
13
+ import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
14
+ import { modifyDeltaProperties, convertMessagesToContent } from '@/messages';
15
+ import { getChatModelClass } from '@/llm/providers';
16
+ import { resetIfNotEmpty, joinKeys } from '@/utils';
17
+ import { HandlerRegistry } from '@/events';
18
+
19
+ const { AGENT, TOOLS } = GraphNodeKeys;
20
+ export type GraphNode = GraphNodeKeys | typeof START;
21
+ export type ClientCallback<T extends unknown[]> = (graph: StandardGraph, ...args: T) => void;
22
+ export type ClientCallbacks = {
23
+ [Callback.TOOL_ERROR]?: ClientCallback<[Error, string]>;
24
+ [Callback.TOOL_START]?: ClientCallback<unknown[]>;
25
+ [Callback.TOOL_END]?: ClientCallback<unknown[]>;
26
+ }
27
+ export type SystemCallbacks = {
28
+ [K in keyof ClientCallbacks]: ClientCallbacks[K] extends ClientCallback<infer Args>
29
+ ? (...args: Args) => void
30
+ : never;
31
+ };
32
+
33
+ export abstract class Graph<
34
+ T extends t.BaseGraphState = t.BaseGraphState,
35
+ TNodeName extends string = string,
36
+ > {
37
+ abstract resetValues(): void;
38
+ abstract createGraphState(): t.GraphStateChannels<T>;
39
+ abstract initializeTools(): CustomToolNode<T> | ToolNode<T>;
40
+ abstract initializeModel(): Runnable;
41
+ abstract getRunMessages(): BaseMessage[] | undefined;
42
+ abstract getContentParts(): t.MessageContentComplex[] | undefined;
43
+ abstract generateStepId(stepKey: string): [string, number];
44
+ abstract getKeyList(metadata: Record<string, unknown> | undefined): (string | number | undefined)[];
45
+ abstract getStepKey(metadata: Record<string, unknown> | undefined): string;
46
+ abstract checkKeyList(keyList: (string | number | undefined)[]): boolean;
47
+ abstract getStepIdByKey(stepKey: string, index?: number): string
48
+ abstract getRunStep(stepId: string): t.RunStep | undefined;
49
+ abstract dispatchRunStep(stepKey: string, stepDetails: t.StepDetails): void;
50
+ abstract dispatchRunStepDelta(id: string, delta: t.ToolCallDelta): void;
51
+ abstract dispatchMessageDelta(id: string, delta: t.MessageDelta): void;
52
+ abstract handleToolCallCompleted(data: t.ToolEndData): void;
53
+
54
+ abstract createCallModel(): (state: T, config?: RunnableConfig) => Promise<Partial<T>>;
55
+ abstract createWorkflow(): t.CompiledWorkflow<T, Partial<T>, TNodeName>;
56
+ messageIdsByStepKey: Map<string, string> = new Map();
57
+ prelimMessageIdsByStepKey: Map<string, string> = new Map();
58
+ config: RunnableConfig | undefined;
59
+ contentData: t.RunStep[] = [];
60
+ stepKeyIds: Map<string, string[]> = new Map<string, string[]>();
61
+ contentIndexMap: Map<string, number> = new Map();
62
+ toolCallStepIds: Map<string, string> = new Map();
63
+ }
64
+
65
+ export class StandardGraph extends Graph<
66
+ t.BaseGraphState,
67
+ GraphNode
68
+ > {
69
+ private graphState: t.GraphStateChannels<t.BaseGraphState>;
70
+ private clientOptions: Record<string, unknown>;
71
+ private boundModel: Runnable;
72
+ handlerRegistry: HandlerRegistry | undefined;
73
+ systemMessage: SystemMessage | undefined;
74
+ messages: BaseMessage[] = [];
75
+ runId: string | undefined;
76
+ tools?: t.GenericTool[];
77
+ toolMap?: t.ToolMap;
78
+ startIndex: number = 0;
79
+ provider: Providers;
80
+
81
+ constructor({
82
+ runId,
83
+ tools,
84
+ toolMap,
85
+ provider,
86
+ clientOptions,
87
+ instructions,
88
+ additional_instructions,
89
+ } : {
90
+ runId?: string;
91
+ provider: Providers;
92
+ tools?: t.GenericTool[];
93
+ toolMap?: t.ToolMap;
94
+ clientOptions: Record<string, unknown>;
95
+ instructions?: string;
96
+ additional_instructions?: string;
97
+ }) {
98
+ super();
99
+ this.runId = runId;
100
+ this.tools = tools;
101
+ this.toolMap = toolMap;
102
+ this.provider = provider;
103
+ this.clientOptions = clientOptions;
104
+ this.graphState = this.createGraphState();
105
+ this.boundModel = this.initializeModel();
106
+
107
+ let finalInstructions = instructions;
108
+ if (additional_instructions) {
109
+ finalInstructions = finalInstructions ? `${finalInstructions}\n\n${additional_instructions}` : additional_instructions;
110
+ }
111
+
112
+ if (finalInstructions) {
113
+ this.systemMessage = new SystemMessage(finalInstructions);
114
+ }
115
+ }
116
+
117
+ /* Init */
118
+
119
+ resetValues(): void {
120
+ this.messages = [];
121
+ this.config = resetIfNotEmpty(this.config, undefined);
122
+ this.contentData = resetIfNotEmpty(this.contentData, []);
123
+ this.stepKeyIds = resetIfNotEmpty(this.stepKeyIds, new Map());
124
+ this.toolCallStepIds = resetIfNotEmpty(this.toolCallStepIds, new Map());
125
+ this.contentIndexMap = resetIfNotEmpty(this.contentIndexMap, new Map());
126
+ this.messageIdsByStepKey = resetIfNotEmpty(this.messageIdsByStepKey, new Map());
127
+ this.prelimMessageIdsByStepKey = resetIfNotEmpty(this.prelimMessageIdsByStepKey, new Map());
128
+ }
129
+
130
+ /* Run Step Processing */
131
+
132
+ getRunStep(stepId: string): t.RunStep | undefined {
133
+ const index = this.contentIndexMap.get(stepId);
134
+ if (index !== undefined) {
135
+ return this.contentData[index];
136
+ }
137
+ return undefined;
138
+ }
139
+
140
+ getStepKey(metadata: Record<string, unknown> | undefined): string {
141
+ if (!metadata) return '';
142
+
143
+ const keyList = this.getKeyList(metadata);
144
+ if (this.checkKeyList(keyList)) {
145
+ throw new Error('Missing metadata');
146
+ }
147
+
148
+ return joinKeys(keyList);
149
+ }
150
+
151
+ getStepIdByKey(stepKey: string, index?: number): string {
152
+ const stepIds = this.stepKeyIds.get(stepKey);
153
+ if (!stepIds) {
154
+ throw new Error(`No step IDs found for stepKey ${stepKey}`);
155
+ }
156
+
157
+ if (index === undefined) {
158
+ return stepIds[stepIds.length - 1];
159
+ }
160
+
161
+ return stepIds[index];
162
+ }
163
+
164
+ generateStepId(stepKey: string): [string, number] {
165
+ const stepIds = this.stepKeyIds.get(stepKey);
166
+ let newStepId: string | undefined;
167
+ let stepIndex = 0;
168
+ if (stepIds) {
169
+ stepIndex = stepIds.length;
170
+ newStepId = `step_${nanoid()}`;
171
+ stepIds.push(newStepId);
172
+ this.stepKeyIds.set(stepKey, stepIds);
173
+ } else {
174
+ newStepId = `step_${nanoid()}`;
175
+ this.stepKeyIds.set(stepKey, [newStepId]);
176
+ }
177
+
178
+ return [newStepId, stepIndex];
179
+ }
180
+
181
+ getKeyList(metadata: Record<string, unknown> | undefined): (string | number | undefined)[] {
182
+ if (!metadata) return [];
183
+
184
+ return [
185
+ metadata.thread_id as string,
186
+ metadata.langgraph_node as string,
187
+ metadata.langgraph_step as number,
188
+ metadata.langgraph_task_idx as number,
189
+ ];
190
+ }
191
+
192
+ checkKeyList(keyList: (string | number | undefined)[]): boolean {
193
+ return keyList.some((key) => key === undefined);
194
+ }
195
+
196
+ /* Misc.*/
197
+
198
+ getRunMessages(): BaseMessage[] | undefined {
199
+ return this.messages.slice(this.startIndex);
200
+ }
201
+
202
+ getContentParts(): t.MessageContentComplex[] | undefined {
203
+ return convertMessagesToContent(this.messages.slice(this.startIndex));
204
+ }
205
+
206
+ /* Graph */
207
+
208
+ createGraphState(): t.GraphStateChannels<t.BaseGraphState> {
209
+ return {
210
+ messages: {
211
+ value: (x: BaseMessage[], y: BaseMessage[]): BaseMessage[] => {
212
+ if (!x.length) {
213
+ if (this.systemMessage) {
214
+ x.push(this.systemMessage);
215
+ }
216
+
217
+ this.startIndex = x.length + y.length;
218
+ }
219
+ const current = x.concat(y);
220
+ this.messages = current;
221
+ return current;
222
+ },
223
+ default: () => [],
224
+ },
225
+ };
226
+ }
227
+
228
+ initializeTools(): CustomToolNode<t.BaseGraphState> | ToolNode<t.BaseGraphState> {
229
+ // return new ToolNode<t.BaseGraphState>(this.tools);
230
+ return new CustomToolNode<t.BaseGraphState>({
231
+ tools: this.tools || [],
232
+ toolMap: this.toolMap,
233
+ });
234
+ }
235
+
236
+ initializeModel(): Runnable {
237
+ const ChatModelClass = getChatModelClass(this.provider);
238
+ const model = new ChatModelClass(this.clientOptions);
239
+ if (!this.tools || this.tools.length === 0) {
240
+ return model;
241
+ }
242
+ return model.bindTools(this.tools as StructuredTool[]);
243
+ }
244
+
245
+ createCallModel() {
246
+ return async (state: t.BaseGraphState, config?: RunnableConfig): Promise<Partial<t.BaseGraphState>> => {
247
+ const { provider } = (config?.configurable as t.GraphConfig) ?? {} ;
248
+ if (!config || !provider) {
249
+ throw new Error(`No ${config ? 'provider' : 'config'} provided`);
250
+ }
251
+ this.config = config;
252
+ const { messages } = state;
253
+
254
+ const finalMessages = messages;
255
+ const lastMessageX = finalMessages[finalMessages.length - 2];
256
+ const lastMessageY = finalMessages[finalMessages.length - 1];
257
+
258
+ if (
259
+ provider === Providers.AWS
260
+ && lastMessageX instanceof AIMessageChunk
261
+ && lastMessageY instanceof ToolMessage
262
+ && typeof lastMessageX.content === 'string'
263
+ ) {
264
+ finalMessages[finalMessages.length - 2].content = '';
265
+ }
266
+
267
+ if (this.tools?.length && (provider === Providers.ANTHROPIC || provider === Providers.AWS)) {
268
+ const stream = await this.boundModel.stream(finalMessages, config);
269
+ let finalChunk: AIMessageChunk | undefined;
270
+ for await (const chunk of stream) {
271
+ dispatchCustomEvent(GraphEvents.CHAT_MODEL_STREAM, { chunk }, config);
272
+ if (!finalChunk) {
273
+ finalChunk = chunk;
274
+ } else {
275
+ finalChunk = concat(finalChunk, chunk);
276
+ }
277
+ }
278
+
279
+ finalChunk = modifyDeltaProperties(finalChunk);
280
+ return { messages: [finalChunk as AIMessageChunk] };
281
+ }
282
+
283
+ const finalMessage = await this.boundModel.invoke(finalMessages, config);
284
+ return { messages: [finalMessage as AIMessageChunk] };
285
+ };
286
+ }
287
+
288
+ createWorkflow(): t.CompiledWorkflow<t.BaseGraphState, Partial<t.BaseGraphState>, GraphNode> {
289
+ const routeMessage = (state: t.BaseGraphState, config?: RunnableConfig): string => {
290
+ this.config = config;
291
+ // const lastMessage = state.messages[state.messages.length - 1] as AIMessage;
292
+ // if (!lastMessage?.tool_calls?.length) {
293
+ // return END;
294
+ // }
295
+ // return TOOLS;
296
+ return toolsCondition(state);
297
+ };
298
+
299
+ const workflow = new StateGraph<t.BaseGraphState, Partial<t.BaseGraphState>, GraphNode>({
300
+ channels: this.graphState,
301
+ })
302
+ .addNode(AGENT, this.createCallModel())
303
+ .addNode(TOOLS, this.initializeTools())
304
+ .addEdge(START, AGENT)
305
+ .addConditionalEdges(AGENT, routeMessage)
306
+ .addEdge(TOOLS, AGENT);
307
+
308
+ return workflow.compile();
309
+ }
310
+
311
+ /* Dispatchers */
312
+
313
+ dispatchRunStep(stepKey: string, stepDetails: t.StepDetails): void {
314
+ if (!this.config) {
315
+ throw new Error('No config provided');
316
+ }
317
+
318
+ const [stepId, stepIndex] = this.generateStepId(stepKey);
319
+ if (stepDetails.type === StepTypes.TOOL_CALLS && stepDetails.tool_calls) {
320
+ for (const tool_call of stepDetails.tool_calls) {
321
+ if (!tool_call.id || this.toolCallStepIds.has(tool_call.id)) {
322
+ continue;
323
+ }
324
+ this.toolCallStepIds.set(tool_call.id, stepId);
325
+ }
326
+ }
327
+
328
+ const runStep: t.RunStep = {
329
+ stepIndex,
330
+ id: stepId,
331
+ type: stepDetails.type,
332
+ index: this.contentData.length,
333
+ stepDetails,
334
+ usage: null,
335
+ };
336
+
337
+ if (this.runId) {
338
+ runStep.runId = this.runId;
339
+ }
340
+
341
+ this.contentData.push(runStep);
342
+ this.contentIndexMap.set(stepId, runStep.index);
343
+ dispatchCustomEvent(GraphEvents.ON_RUN_STEP, runStep, this.config);
344
+ }
345
+
346
+ handleToolCallCompleted(data: t.ToolEndData, metadata?: Record<string, unknown>): void {
347
+ if (!this.config) {
348
+ throw new Error('No config provided');
349
+ }
350
+
351
+ const { input, output } = data;
352
+ const { tool_call_id } = output;
353
+ const stepId = this.toolCallStepIds.get(tool_call_id);
354
+ if (!stepId) {
355
+ throw new Error(`No stepId found for tool_call_id ${tool_call_id}`);
356
+ }
357
+ const runStep = this.getRunStep(stepId);
358
+ if (!runStep) {
359
+ throw new Error(`No run step found for stepId ${stepId}`);
360
+ }
361
+
362
+ if (!data?.output) {
363
+ // console.warn('No output found in tool_end event');
364
+ // console.dir(data, { depth: null });
365
+ return;
366
+ }
367
+
368
+ const args = typeof input === 'string' ? input : input.input;
369
+ const tool_call = {
370
+ args: typeof args === 'string' ? args : JSON.stringify(args),
371
+ name: output.name ?? '',
372
+ id: output.tool_call_id,
373
+ output: typeof output.content === 'string'
374
+ ? output.content
375
+ : JSON.stringify(output.content),
376
+ progress: 1,
377
+ };
378
+
379
+ this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED)?.handle(
380
+ GraphEvents.ON_RUN_STEP_COMPLETED,
381
+ { result: {
382
+ id: stepId,
383
+ index: runStep.index,
384
+ type: 'tool_call',
385
+ tool_call
386
+ } as t.ToolCompleteEvent,
387
+ },
388
+ metadata,
389
+ this,
390
+ );
391
+ }
392
+
393
+ dispatchRunStepDelta(id: string, delta: t.ToolCallDelta): void {
394
+ if (!this.config) {
395
+ throw new Error('No config provided');
396
+ } else if (!id) {
397
+ throw new Error('No step ID found');
398
+ }
399
+ const runStepDelta: t.RunStepDeltaEvent = {
400
+ id,
401
+ delta,
402
+ };
403
+ dispatchCustomEvent(GraphEvents.ON_RUN_STEP_DELTA, runStepDelta, this.config);
404
+ }
405
+
406
+ dispatchMessageDelta(id: string, delta: t.MessageDelta): void {
407
+ if (!this.config) {
408
+ throw new Error('No config provided');
409
+ }
410
+ const messageDelta: t.MessageDeltaEvent = {
411
+ id,
412
+ delta,
413
+ };
414
+ dispatchCustomEvent(GraphEvents.ON_MESSAGE_DELTA, messageDelta, this.config);
415
+ }
416
+ }
@@ -0,0 +1 @@
1
+ export * from './Graph';
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ /* Main Operations */
2
+ export * from './run';
3
+ export * from './stream';
4
+ export * from './events';
5
+ export * from './messages';
6
+
7
+ /* Graphs */
8
+ export * from './graphs';
9
+
10
+ /* Misc. */
11
+ export * from './common';
12
+ export * from './utils';
13
+
14
+ /* Types */
15
+ export type * from './types';
@@ -0,0 +1,27 @@
1
+ // src/llm/providers.ts
2
+ import { ChatOpenAI } from '@langchain/openai';
3
+ import { ChatBedrockConverse } from '@langchain/aws';
4
+ import { ChatAnthropic } from '@langchain/anthropic';
5
+ import { ChatMistralAI } from '@langchain/mistralai';
6
+ import { ChatVertexAI } from '@langchain/google-vertexai';
7
+ import { BedrockChat } from '@langchain/community/chat_models/bedrock/web';
8
+ import type * as t from '@/types';
9
+ import { Providers } from '@/common';
10
+
11
+ export const llmProviders: Record<Providers, t.ChatModelConstructor> = {
12
+ [Providers.OPENAI]: ChatOpenAI,
13
+ [Providers.VERTEXAI]: ChatVertexAI,
14
+ [Providers.BEDROCK]: BedrockChat as unknown as t.ChatModelConstructor,
15
+ [Providers.MISTRALAI]: ChatMistralAI,
16
+ [Providers.AWS]: ChatBedrockConverse as unknown as t.ChatModelConstructor,
17
+ [Providers.ANTHROPIC]: ChatAnthropic,
18
+ };
19
+
20
+ export const getChatModelClass = (provider: Providers): t.ChatModelConstructor => {
21
+ const ChatModelClass = llmProviders[provider];
22
+ if (!ChatModelClass) {
23
+ throw new Error(`Unsupported LLM provider: ${provider}`);
24
+ }
25
+
26
+ return ChatModelClass;
27
+ };
@@ -0,0 +1,210 @@
1
+ // src/messages.ts
2
+ import { AIMessageChunk, HumanMessage, ToolMessage, AIMessage, BaseMessage } from '@langchain/core/messages';
3
+ import type { ToolCall } from '@langchain/core/messages/tool';
4
+ import type * as t from '@/types';
5
+
6
+ export function getConverseOverrideMessage({
7
+ userMessage,
8
+ lastMessageX,
9
+ lastMessageY
10
+ }: {
11
+ userMessage: string[];
12
+ lastMessageX: AIMessageChunk;
13
+ lastMessageY: ToolMessage;
14
+ }): HumanMessage {
15
+ const content = `
16
+ User: ${userMessage[1]}
17
+
18
+ ---
19
+ # YOU HAVE ALREADY RESPONDED TO THE LATEST USER MESSAGE:
20
+
21
+ # Observations:
22
+ - ${lastMessageX.content}
23
+
24
+ # Tool Calls:
25
+ - ${lastMessageX?.tool_calls?.join('\n- ')}
26
+
27
+ # Tool Responses:
28
+ - ${lastMessageY.content}
29
+ `;
30
+
31
+ return new HumanMessage(content);
32
+ }
33
+
34
+ const modifyContent = (messageType: string, content: t.ExtendedMessageContent[]): t.ExtendedMessageContent[] => {
35
+ return content.map(item => {
36
+ if (item && typeof item === 'object' && 'type' in item && item.type) {
37
+ let newType = item.type;
38
+ if (newType.endsWith('_delta')) {
39
+ newType = newType.replace('_delta', '');
40
+ }
41
+ const allowedTypes = ['image_url', 'text', 'tool_use', 'tool_result'];
42
+ if (!allowedTypes.includes(newType)) {
43
+ newType = 'text';
44
+ }
45
+
46
+ /* Handle the edge case for empty object 'tool_use' input in AI messages */
47
+ if (messageType === 'ai' && newType === 'tool_use' && 'input' in item && item.input === '') {
48
+ return { ...item, type: newType, input: '{}' };
49
+ }
50
+
51
+ return { ...item, type: newType };
52
+ }
53
+ return item;
54
+ });
55
+ };
56
+
57
+ export function modifyDeltaProperties(obj?: AIMessageChunk): AIMessageChunk | undefined {
58
+ if (!obj || typeof obj !== 'object') return obj;
59
+
60
+ const messageType = obj._getType ? obj._getType() : '';
61
+
62
+ if (Array.isArray(obj.content)) {
63
+ obj.content = modifyContent(messageType, obj.content);
64
+ }
65
+ if (obj.lc_kwargs && Array.isArray(obj.lc_kwargs.content)) {
66
+ obj.lc_kwargs.content = modifyContent(messageType, obj.lc_kwargs.content);
67
+ }
68
+ return obj;
69
+ }
70
+
71
+ export function formatAnthropicMessage(message: AIMessageChunk): AIMessage {
72
+ if (!message.tool_calls || message.tool_calls.length === 0) {
73
+ return new AIMessage({ content: message.content });
74
+ }
75
+
76
+ const toolCallMap = new Map(message.tool_calls.map(tc => [tc.id, tc]));
77
+ let formattedContent: string | t.ExtendedMessageContent[];
78
+
79
+ if (Array.isArray(message.content)) {
80
+ formattedContent = message.content.reduce<t.ExtendedMessageContent[]>((acc, item) => {
81
+ if (typeof item === 'object' && item !== null) {
82
+ const extendedItem = item as t.ExtendedMessageContent;
83
+ if (extendedItem.type === 'text' && extendedItem.text) {
84
+ acc.push({ type: 'text', text: extendedItem.text });
85
+ } else if (extendedItem.type === 'tool_use' && extendedItem.id) {
86
+ const toolCall = toolCallMap.get(extendedItem.id);
87
+ if (toolCall) {
88
+ acc.push({
89
+ type: 'tool_use',
90
+ id: extendedItem.id,
91
+ name: toolCall.name,
92
+ input: toolCall.args as unknown as string
93
+ });
94
+ }
95
+ } else if ('input' in extendedItem && extendedItem.input) {
96
+ try {
97
+ const parsedInput = JSON.parse(extendedItem.input);
98
+ const toolCall = message.tool_calls?.find(tc => tc.args.input === parsedInput.input);
99
+ if (toolCall) {
100
+ acc.push({
101
+ type: 'tool_use',
102
+ id: toolCall.id,
103
+ name: toolCall.name,
104
+ input: toolCall.args as unknown as string
105
+ });
106
+ }
107
+ } catch (e) {
108
+ if (extendedItem.input) {
109
+ acc.push({ type: 'text', text: extendedItem.input });
110
+ }
111
+ }
112
+ }
113
+ } else if (typeof item === 'string') {
114
+ acc.push({ type: 'text', text: item });
115
+ }
116
+ return acc;
117
+ }, []);
118
+ } else if (typeof message.content === 'string') {
119
+ formattedContent = message.content;
120
+ } else {
121
+ formattedContent = [];
122
+ }
123
+
124
+ // const formattedToolCalls: ToolCall[] = message.tool_calls.map(toolCall => ({
125
+ // id: toolCall.id ?? '',
126
+ // name: toolCall.name,
127
+ // args: toolCall.args,
128
+ // type: 'tool_call',
129
+ // }));
130
+
131
+ const formattedToolCalls: t.AgentToolCall[] = message.tool_calls.map(toolCall => ({
132
+ id: toolCall.id ?? '',
133
+ type: 'function',
134
+ function: {
135
+ name: toolCall.name,
136
+ arguments: toolCall.args
137
+ }
138
+ }));
139
+
140
+ return new AIMessage({
141
+ content: formattedContent,
142
+ tool_calls: formattedToolCalls as ToolCall[],
143
+ additional_kwargs: {
144
+ ...message.additional_kwargs,
145
+ }
146
+ });
147
+ }
148
+
149
+ export function convertMessagesToContent(messages: BaseMessage[]): t.MessageContentComplex[] {
150
+ const processedContent: t.MessageContentComplex[] = [];
151
+
152
+ const addContentPart = (message: BaseMessage): void => {
153
+ const content = message?.content;
154
+ if (content === undefined) {
155
+ return;
156
+ }
157
+ if (typeof content === 'string') {
158
+ processedContent.push({
159
+ type: 'text',
160
+ text: content
161
+ });
162
+ } else if (Array.isArray(content)) {
163
+ const filteredContent = content.filter(item => item && item.type !== 'tool_use');
164
+ processedContent.push(...filteredContent);
165
+ }
166
+ };
167
+
168
+ let currentAIMessageIndex = -1;
169
+ const toolCallMap = new Map<string, t.CustomToolCall>();
170
+
171
+ for (let i = 0; i < messages.length; i++) {
172
+ const message = messages[i];
173
+ const messageType = message?._getType();
174
+
175
+ if (messageType === 'ai' && (message as AIMessage).tool_calls?.length) {
176
+ const tool_calls = (message as AIMessage).tool_calls || [];
177
+ for (const tool_call of tool_calls) {
178
+ if (!tool_call.id) {
179
+ continue;
180
+ }
181
+
182
+ toolCallMap.set(tool_call.id, tool_call);
183
+ }
184
+
185
+ addContentPart(message);
186
+ currentAIMessageIndex = processedContent.length - 1;
187
+ continue;
188
+ } else if (messageType === 'tool' && (message as ToolMessage).tool_call_id) {
189
+ const id = (message as ToolMessage).tool_call_id;
190
+ const output = (message as ToolMessage).content;
191
+ const tool_call = toolCallMap.get(id);
192
+
193
+ processedContent.push({
194
+ type: 'tool_call',
195
+ tool_call: Object.assign({}, tool_call, { output }),
196
+ });
197
+ const contentPart = processedContent[currentAIMessageIndex];
198
+ const tool_call_ids = contentPart.tool_call_ids || [];
199
+ tool_call_ids.push(id);
200
+ contentPart.tool_call_ids = tool_call_ids;
201
+ continue;
202
+ } else if (messageType !== 'ai') {
203
+ continue;
204
+ }
205
+
206
+ addContentPart(message);
207
+ }
208
+
209
+ return processedContent;
210
+ }
@@ -0,0 +1,6 @@
1
+ // src/prompts/collab.ts
2
+ export const supervisorPrompt = `You are a supervisor tasked with managing a conversation between the
3
+ following workers: {members}. Given the following user request,
4
+ respond with the worker to act next. Each worker will perform a
5
+ task and respond with their results and status. Multiple workers can work at once, and they can use multiple tools at once. Each worker can run their tools multiple times per task. When finished,
6
+ respond with FINISH.`;
@@ -0,0 +1,2 @@
1
+ export * from './collab';
2
+ export * from './taskmanager';