@librechat/agents 2.4.322 → 3.0.0-rc2
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/agents/AgentContext.cjs +218 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -0
- package/dist/cjs/common/enum.cjs +14 -5
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -6
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +309 -212
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +422 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/index.cjs +54 -9
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +52 -6
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +22 -2
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/tools.cjs +29 -0
- package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -0
- package/dist/cjs/llm/google/index.cjs +144 -0
- package/dist/cjs/llm/google/index.cjs.map +1 -0
- package/dist/cjs/llm/google/utils/common.cjs +477 -0
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -0
- package/dist/cjs/llm/ollama/index.cjs +67 -0
- package/dist/cjs/llm/ollama/index.cjs.map +1 -0
- package/dist/cjs/llm/ollama/utils.cjs +158 -0
- package/dist/cjs/llm/ollama/utils.cjs.map +1 -0
- package/dist/cjs/llm/openai/index.cjs +389 -3
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +672 -0
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +15 -15
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/text.cjs +14 -3
- package/dist/cjs/llm/text.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs +330 -0
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -0
- package/dist/cjs/main.cjs +11 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/run.cjs +120 -81
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +85 -51
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +10 -4
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +119 -13
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/search/anthropic.cjs +40 -0
- package/dist/cjs/tools/search/anthropic.cjs.map +1 -0
- package/dist/cjs/tools/search/firecrawl.cjs +55 -9
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/format.cjs +6 -6
- package/dist/cjs/tools/search/format.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +7 -29
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +86 -16
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +4 -2
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs +1 -1
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/cjs/utils/events.cjs +31 -0
- package/dist/cjs/utils/events.cjs.map +1 -0
- package/dist/cjs/utils/title.cjs +57 -21
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +54 -7
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +216 -0
- package/dist/esm/agents/AgentContext.mjs.map +1 -0
- package/dist/esm/common/enum.mjs +15 -6
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -6
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +311 -214
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +420 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
- package/dist/esm/llm/anthropic/index.mjs +54 -9
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/types.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +52 -6
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +22 -2
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/tools.mjs +27 -0
- package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -0
- package/dist/esm/llm/google/index.mjs +142 -0
- package/dist/esm/llm/google/index.mjs.map +1 -0
- package/dist/esm/llm/google/utils/common.mjs +471 -0
- package/dist/esm/llm/google/utils/common.mjs.map +1 -0
- package/dist/esm/llm/ollama/index.mjs +65 -0
- package/dist/esm/llm/ollama/index.mjs.map +1 -0
- package/dist/esm/llm/ollama/utils.mjs +155 -0
- package/dist/esm/llm/ollama/utils.mjs.map +1 -0
- package/dist/esm/llm/openai/index.mjs +388 -4
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +666 -0
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +5 -5
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/text.mjs +14 -3
- package/dist/esm/llm/text.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs +328 -0
- package/dist/esm/llm/vertexai/index.mjs.map +1 -0
- package/dist/esm/main.mjs +6 -5
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/run.mjs +121 -83
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +87 -54
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +10 -4
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +119 -15
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/search/anthropic.mjs +37 -0
- package/dist/esm/tools/search/anthropic.mjs.map +1 -0
- package/dist/esm/tools/search/firecrawl.mjs +55 -9
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/format.mjs +7 -7
- package/dist/esm/tools/search/format.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +7 -29
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +86 -16
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +4 -2
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs +1 -1
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/esm/utils/events.mjs +29 -0
- package/dist/esm/utils/events.mjs.map +1 -0
- package/dist/esm/utils/title.mjs +57 -22
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +54 -8
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +91 -0
- package/dist/types/common/enum.d.ts +15 -6
- package/dist/types/events.d.ts +5 -4
- package/dist/types/graphs/Graph.d.ts +64 -67
- package/dist/types/graphs/MultiAgentGraph.d.ts +37 -0
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/llm/anthropic/index.d.ts +11 -0
- package/dist/types/llm/anthropic/types.d.ts +9 -3
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
- package/dist/types/llm/anthropic/utils/output_parsers.d.ts +4 -4
- package/dist/types/llm/anthropic/utils/tools.d.ts +3 -0
- package/dist/types/llm/google/index.d.ts +13 -0
- package/dist/types/llm/google/types.d.ts +32 -0
- package/dist/types/llm/google/utils/common.d.ts +19 -0
- package/dist/types/llm/google/utils/tools.d.ts +10 -0
- package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +14 -0
- package/dist/types/llm/ollama/index.d.ts +7 -0
- package/dist/types/llm/ollama/utils.d.ts +7 -0
- package/dist/types/llm/openai/index.d.ts +72 -3
- package/dist/types/llm/openai/types.d.ts +10 -0
- package/dist/types/llm/openai/utils/index.d.ts +20 -0
- package/dist/types/llm/text.d.ts +1 -1
- package/dist/types/llm/vertexai/index.d.ts +293 -0
- package/dist/types/messages/reducer.d.ts +9 -0
- package/dist/types/run.d.ts +19 -12
- package/dist/types/scripts/ant_web_search.d.ts +1 -0
- package/dist/types/scripts/args.d.ts +2 -1
- package/dist/types/scripts/handoff-test.d.ts +1 -0
- package/dist/types/scripts/multi-agent-conditional.d.ts +1 -0
- package/dist/types/scripts/multi-agent-parallel.d.ts +1 -0
- package/dist/types/scripts/multi-agent-sequence.d.ts +1 -0
- package/dist/types/scripts/multi-agent-supervisor.d.ts +1 -0
- package/dist/types/scripts/multi-agent-test.d.ts +1 -0
- package/dist/types/scripts/test-custom-prompt-key.d.ts +2 -0
- package/dist/types/scripts/test-handoff-input.d.ts +2 -0
- package/dist/types/scripts/test-multi-agent-list-handoff.d.ts +2 -0
- package/dist/types/stream.d.ts +10 -3
- package/dist/types/tools/CodeExecutor.d.ts +2 -2
- package/dist/types/tools/ToolNode.d.ts +1 -1
- package/dist/types/tools/handlers.d.ts +17 -4
- package/dist/types/tools/search/anthropic.d.ts +16 -0
- package/dist/types/tools/search/firecrawl.d.ts +15 -0
- package/dist/types/tools/search/rerankers.d.ts +0 -1
- package/dist/types/tools/search/types.d.ts +30 -9
- package/dist/types/types/graph.d.ts +129 -15
- package/dist/types/types/llm.d.ts +24 -10
- package/dist/types/types/run.d.ts +46 -8
- package/dist/types/types/stream.d.ts +16 -2
- package/dist/types/types/tools.d.ts +1 -1
- package/dist/types/utils/events.d.ts +6 -0
- package/dist/types/utils/title.d.ts +2 -1
- package/dist/types/utils/tokens.d.ts +24 -0
- package/package.json +37 -17
- package/src/agents/AgentContext.ts +315 -0
- package/src/common/enum.ts +14 -5
- package/src/events.ts +24 -13
- package/src/graphs/Graph.ts +495 -312
- package/src/graphs/MultiAgentGraph.ts +498 -0
- package/src/graphs/index.ts +2 -1
- package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
- package/src/llm/anthropic/index.ts +78 -13
- package/src/llm/anthropic/llm.spec.ts +491 -115
- package/src/llm/anthropic/types.ts +39 -3
- package/src/llm/anthropic/utils/message_inputs.ts +67 -11
- package/src/llm/anthropic/utils/message_outputs.ts +21 -2
- package/src/llm/anthropic/utils/output_parsers.ts +25 -6
- package/src/llm/anthropic/utils/tools.ts +29 -0
- package/src/llm/google/index.ts +218 -0
- package/src/llm/google/types.ts +43 -0
- package/src/llm/google/utils/common.ts +646 -0
- package/src/llm/google/utils/tools.ts +160 -0
- package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
- package/src/llm/ollama/index.ts +89 -0
- package/src/llm/ollama/utils.ts +193 -0
- package/src/llm/openai/index.ts +600 -14
- package/src/llm/openai/types.ts +24 -0
- package/src/llm/openai/utils/index.ts +912 -0
- package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
- package/src/llm/providers.ts +10 -9
- package/src/llm/text.ts +26 -7
- package/src/llm/vertexai/index.ts +360 -0
- package/src/messages/reducer.ts +80 -0
- package/src/run.ts +181 -112
- package/src/scripts/ant_web_search.ts +158 -0
- package/src/scripts/args.ts +12 -8
- package/src/scripts/cli4.ts +29 -21
- package/src/scripts/cli5.ts +29 -21
- package/src/scripts/code_exec.ts +54 -23
- package/src/scripts/code_exec_files.ts +48 -17
- package/src/scripts/code_exec_simple.ts +46 -27
- package/src/scripts/handoff-test.ts +135 -0
- package/src/scripts/image.ts +52 -20
- package/src/scripts/multi-agent-conditional.ts +220 -0
- package/src/scripts/multi-agent-example-output.md +110 -0
- package/src/scripts/multi-agent-parallel.ts +341 -0
- package/src/scripts/multi-agent-sequence.ts +212 -0
- package/src/scripts/multi-agent-supervisor.ts +361 -0
- package/src/scripts/multi-agent-test.ts +186 -0
- package/src/scripts/search.ts +1 -9
- package/src/scripts/simple.ts +25 -10
- package/src/scripts/test-custom-prompt-key.ts +145 -0
- package/src/scripts/test-handoff-input.ts +110 -0
- package/src/scripts/test-multi-agent-list-handoff.ts +258 -0
- package/src/scripts/tools.ts +48 -18
- package/src/specs/anthropic.simple.test.ts +150 -34
- package/src/specs/azure.simple.test.ts +325 -0
- package/src/specs/openai.simple.test.ts +140 -33
- package/src/specs/openrouter.simple.test.ts +107 -0
- package/src/specs/prune.test.ts +4 -9
- package/src/specs/reasoning.test.ts +80 -44
- package/src/specs/token-memoization.test.ts +39 -0
- package/src/stream.test.ts +94 -0
- package/src/stream.ts +139 -60
- package/src/tools/ToolNode.ts +21 -7
- package/src/tools/handlers.ts +192 -18
- package/src/tools/search/anthropic.ts +51 -0
- package/src/tools/search/firecrawl.ts +69 -20
- package/src/tools/search/format.ts +6 -8
- package/src/tools/search/rerankers.ts +7 -40
- package/src/tools/search/search.ts +97 -16
- package/src/tools/search/tool.ts +5 -2
- package/src/tools/search/types.ts +30 -10
- package/src/tools/search/utils.ts +1 -1
- package/src/types/graph.ts +315 -103
- package/src/types/llm.ts +25 -12
- package/src/types/run.ts +51 -13
- package/src/types/stream.ts +22 -1
- package/src/types/tools.ts +16 -10
- package/src/utils/events.ts +32 -0
- package/src/utils/llmConfig.ts +19 -7
- package/src/utils/title.ts +104 -30
- package/src/utils/tokens.ts +69 -10
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { AIMessageChunk } from '@langchain/core/messages';
|
|
2
|
+
import type { ChatOpenAIReasoningSummary } from '@langchain/openai';
|
|
3
|
+
import { getChunkContent } from './stream';
|
|
4
|
+
import { Providers } from '@/common';
|
|
5
|
+
|
|
6
|
+
describe('getChunkContent', () => {
|
|
7
|
+
it('should handle reasoning content for OpenAI/Azure providers', () => {
|
|
8
|
+
const chunk: Partial<AIMessageChunk> = {
|
|
9
|
+
content: 'Regular content',
|
|
10
|
+
additional_kwargs: {
|
|
11
|
+
reasoning: {
|
|
12
|
+
summary: [{ text: 'Reasoning summary text' }],
|
|
13
|
+
} as Partial<ChatOpenAIReasoningSummary>,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const result = getChunkContent({
|
|
18
|
+
chunk,
|
|
19
|
+
provider: Providers.OPENAI,
|
|
20
|
+
reasoningKey: 'reasoning',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(result).toBe('Reasoning summary text');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should fallback to reasoningKey when no OpenAI reasoning summary', () => {
|
|
27
|
+
const chunk: Partial<AIMessageChunk> = {
|
|
28
|
+
content: 'Regular content',
|
|
29
|
+
additional_kwargs: {
|
|
30
|
+
reasoning_content: 'Reasoning from key',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const result = getChunkContent({
|
|
35
|
+
chunk,
|
|
36
|
+
reasoningKey: 'reasoning_content',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(result).toBe('Reasoning from key');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should fallback to chunk.content when reasoningKey value is null or undefined', () => {
|
|
43
|
+
const chunk: Partial<AIMessageChunk> = {
|
|
44
|
+
content: 'Fallback content',
|
|
45
|
+
additional_kwargs: {
|
|
46
|
+
reasoning_content: null,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const result = getChunkContent({
|
|
51
|
+
chunk,
|
|
52
|
+
reasoningKey: 'reasoning_content',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(result).toBe('Fallback content');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should fallback to chunk.content when reasoningKey value is empty string', () => {
|
|
59
|
+
const chunk: Partial<AIMessageChunk> = {
|
|
60
|
+
content: ' can',
|
|
61
|
+
additional_kwargs: {
|
|
62
|
+
reasoning_content: '',
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const result = getChunkContent({
|
|
67
|
+
chunk,
|
|
68
|
+
reasoningKey: 'reasoning_content',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(result).toBe(' can');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should return undefined when no content is available', () => {
|
|
75
|
+
const chunk: Partial<AIMessageChunk> = {
|
|
76
|
+
additional_kwargs: {},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const result = getChunkContent({
|
|
80
|
+
chunk,
|
|
81
|
+
reasoningKey: 'reasoning',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(result).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should handle missing chunk gracefully', () => {
|
|
88
|
+
const result = getChunkContent({
|
|
89
|
+
reasoningKey: 'reasoning',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(result).toBeUndefined();
|
|
93
|
+
});
|
|
94
|
+
});
|
package/src/stream.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
// src/stream.ts
|
|
2
|
+
import type { ChatOpenAIReasoningSummary } from '@langchain/openai';
|
|
2
3
|
import type { AIMessageChunk } from '@langchain/core/messages';
|
|
3
4
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
4
|
-
import type {
|
|
5
|
+
import type { AgentContext } from '@/agents/AgentContext';
|
|
6
|
+
import type { StandardGraph } from '@/graphs';
|
|
5
7
|
import type * as t from '@/types';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
+
import {
|
|
9
|
+
ToolCallTypes,
|
|
10
|
+
ContentTypes,
|
|
11
|
+
GraphEvents,
|
|
12
|
+
StepTypes,
|
|
13
|
+
Providers,
|
|
14
|
+
} from '@/common';
|
|
15
|
+
import {
|
|
16
|
+
handleServerToolResult,
|
|
17
|
+
handleToolCallChunks,
|
|
18
|
+
handleToolCalls,
|
|
19
|
+
} from '@/tools/handlers';
|
|
8
20
|
import { getMessageId } from '@/messages';
|
|
9
21
|
|
|
10
22
|
/**
|
|
@@ -66,13 +78,48 @@ function getNonEmptyValue(possibleValues: string[]): string | undefined {
|
|
|
66
78
|
}
|
|
67
79
|
return undefined;
|
|
68
80
|
}
|
|
81
|
+
|
|
82
|
+
export function getChunkContent({
|
|
83
|
+
chunk,
|
|
84
|
+
provider,
|
|
85
|
+
reasoningKey,
|
|
86
|
+
}: {
|
|
87
|
+
chunk?: Partial<AIMessageChunk>;
|
|
88
|
+
provider?: Providers;
|
|
89
|
+
reasoningKey: 'reasoning_content' | 'reasoning';
|
|
90
|
+
}): string | t.MessageContentComplex[] | undefined {
|
|
91
|
+
if (
|
|
92
|
+
(provider === Providers.OPENAI || provider === Providers.AZURE) &&
|
|
93
|
+
(
|
|
94
|
+
chunk?.additional_kwargs?.reasoning as
|
|
95
|
+
| Partial<ChatOpenAIReasoningSummary>
|
|
96
|
+
| undefined
|
|
97
|
+
)?.summary?.[0]?.text != null &&
|
|
98
|
+
((
|
|
99
|
+
chunk?.additional_kwargs?.reasoning as
|
|
100
|
+
| Partial<ChatOpenAIReasoningSummary>
|
|
101
|
+
| undefined
|
|
102
|
+
)?.summary?.[0]?.text?.length ?? 0) > 0
|
|
103
|
+
) {
|
|
104
|
+
return (
|
|
105
|
+
chunk?.additional_kwargs?.reasoning as
|
|
106
|
+
| Partial<ChatOpenAIReasoningSummary>
|
|
107
|
+
| undefined
|
|
108
|
+
)?.summary?.[0]?.text;
|
|
109
|
+
}
|
|
110
|
+
return (
|
|
111
|
+
((chunk?.additional_kwargs?.[reasoningKey] as string | undefined) ?? '') ||
|
|
112
|
+
chunk?.content
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
69
116
|
export class ChatModelStreamHandler implements t.EventHandler {
|
|
70
|
-
handle(
|
|
117
|
+
async handle(
|
|
71
118
|
event: string,
|
|
72
119
|
data: t.StreamEventData,
|
|
73
120
|
metadata?: Record<string, unknown>,
|
|
74
|
-
graph?:
|
|
75
|
-
): void {
|
|
121
|
+
graph?: StandardGraph
|
|
122
|
+
): Promise<void> {
|
|
76
123
|
if (!graph) {
|
|
77
124
|
throw new Error('Graph not found');
|
|
78
125
|
}
|
|
@@ -84,12 +131,24 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
84
131
|
return;
|
|
85
132
|
}
|
|
86
133
|
|
|
87
|
-
const
|
|
88
|
-
const content =
|
|
89
|
-
(chunk.additional_kwargs?.[graph.reasoningKey] as string | undefined) ??
|
|
90
|
-
chunk.content;
|
|
91
|
-
this.handleReasoning(chunk, graph);
|
|
134
|
+
const agentContext = graph.getAgentContext(metadata);
|
|
92
135
|
|
|
136
|
+
const chunk = data.chunk as Partial<AIMessageChunk>;
|
|
137
|
+
const content = getChunkContent({
|
|
138
|
+
chunk,
|
|
139
|
+
reasoningKey: agentContext.reasoningKey,
|
|
140
|
+
provider: agentContext.provider,
|
|
141
|
+
});
|
|
142
|
+
const skipHandling = await handleServerToolResult({
|
|
143
|
+
graph,
|
|
144
|
+
content,
|
|
145
|
+
metadata,
|
|
146
|
+
agentContext,
|
|
147
|
+
});
|
|
148
|
+
if (skipHandling) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this.handleReasoning(chunk, agentContext);
|
|
93
152
|
let hasToolCalls = false;
|
|
94
153
|
if (
|
|
95
154
|
chunk.tool_calls &&
|
|
@@ -97,7 +156,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
97
156
|
chunk.tool_calls.every((tc) => tc.id != null && tc.id !== '')
|
|
98
157
|
) {
|
|
99
158
|
hasToolCalls = true;
|
|
100
|
-
handleToolCalls(chunk.tool_calls, metadata, graph);
|
|
159
|
+
await handleToolCalls(chunk.tool_calls, metadata, graph);
|
|
101
160
|
}
|
|
102
161
|
|
|
103
162
|
const hasToolCallChunks =
|
|
@@ -106,18 +165,16 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
106
165
|
typeof content === 'undefined' ||
|
|
107
166
|
!content.length ||
|
|
108
167
|
(typeof content === 'string' && !content);
|
|
109
|
-
const isEmptyChunk = isEmptyContent && !hasToolCallChunks;
|
|
110
|
-
const chunkId = chunk.id ?? '';
|
|
111
|
-
if (isEmptyChunk && chunkId && chunkId.startsWith('msg')) {
|
|
112
|
-
if (graph.messageIdsByStepKey.has(chunkId)) {
|
|
113
|
-
return;
|
|
114
|
-
} else if (graph.prelimMessageIdsByStepKey.has(chunkId)) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
168
|
|
|
169
|
+
/** Set a preliminary message ID if found in empty chunk */
|
|
170
|
+
const isEmptyChunk = isEmptyContent && !hasToolCallChunks;
|
|
171
|
+
if (
|
|
172
|
+
isEmptyChunk &&
|
|
173
|
+
(chunk.id ?? '') !== '' &&
|
|
174
|
+
!graph.prelimMessageIdsByStepKey.has(chunk.id ?? '')
|
|
175
|
+
) {
|
|
118
176
|
const stepKey = graph.getStepKey(metadata);
|
|
119
|
-
graph.prelimMessageIdsByStepKey.set(stepKey,
|
|
120
|
-
return;
|
|
177
|
+
graph.prelimMessageIdsByStepKey.set(stepKey, chunk.id ?? '');
|
|
121
178
|
} else if (isEmptyChunk) {
|
|
122
179
|
return;
|
|
123
180
|
}
|
|
@@ -130,7 +187,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
130
187
|
chunk.tool_call_chunks.length &&
|
|
131
188
|
typeof chunk.tool_call_chunks[0]?.index === 'number'
|
|
132
189
|
) {
|
|
133
|
-
handleToolCallChunks({
|
|
190
|
+
await handleToolCallChunks({
|
|
134
191
|
graph,
|
|
135
192
|
stepKey,
|
|
136
193
|
toolCallChunks: chunk.tool_call_chunks,
|
|
@@ -143,7 +200,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
143
200
|
|
|
144
201
|
const message_id = getMessageId(stepKey, graph) ?? '';
|
|
145
202
|
if (message_id) {
|
|
146
|
-
graph.dispatchRunStep(stepKey, {
|
|
203
|
+
await graph.dispatchRunStep(stepKey, {
|
|
147
204
|
type: StepTypes.MESSAGE_CREATION,
|
|
148
205
|
message_creation: {
|
|
149
206
|
message_id,
|
|
@@ -181,8 +238,8 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
181
238
|
) {
|
|
182
239
|
return;
|
|
183
240
|
} else if (typeof content === 'string') {
|
|
184
|
-
if (
|
|
185
|
-
graph.dispatchMessageDelta(stepId, {
|
|
241
|
+
if (agentContext.currentTokenType === ContentTypes.TEXT) {
|
|
242
|
+
await graph.dispatchMessageDelta(stepId, {
|
|
186
243
|
content: [
|
|
187
244
|
{
|
|
188
245
|
type: ContentTypes.TEXT,
|
|
@@ -190,10 +247,10 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
190
247
|
},
|
|
191
248
|
],
|
|
192
249
|
});
|
|
193
|
-
} else if (
|
|
250
|
+
} else if (agentContext.currentTokenType === 'think_and_text') {
|
|
194
251
|
const { text, thinking } = parseThinkingContent(content);
|
|
195
252
|
if (thinking) {
|
|
196
|
-
graph.dispatchReasoningDelta(stepId, {
|
|
253
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
197
254
|
content: [
|
|
198
255
|
{
|
|
199
256
|
type: ContentTypes.THINK,
|
|
@@ -203,11 +260,11 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
203
260
|
});
|
|
204
261
|
}
|
|
205
262
|
if (text) {
|
|
206
|
-
|
|
207
|
-
|
|
263
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
264
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
208
265
|
const newStepKey = graph.getStepKey(metadata);
|
|
209
266
|
const message_id = getMessageId(newStepKey, graph) ?? '';
|
|
210
|
-
graph.dispatchRunStep(newStepKey, {
|
|
267
|
+
await graph.dispatchRunStep(newStepKey, {
|
|
211
268
|
type: StepTypes.MESSAGE_CREATION,
|
|
212
269
|
message_creation: {
|
|
213
270
|
message_id,
|
|
@@ -215,7 +272,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
215
272
|
});
|
|
216
273
|
|
|
217
274
|
const newStepId = graph.getStepIdByKey(newStepKey);
|
|
218
|
-
graph.dispatchMessageDelta(newStepId, {
|
|
275
|
+
await graph.dispatchMessageDelta(newStepId, {
|
|
219
276
|
content: [
|
|
220
277
|
{
|
|
221
278
|
type: ContentTypes.TEXT,
|
|
@@ -225,7 +282,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
225
282
|
});
|
|
226
283
|
}
|
|
227
284
|
} else {
|
|
228
|
-
graph.dispatchReasoningDelta(stepId, {
|
|
285
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
229
286
|
content: [
|
|
230
287
|
{
|
|
231
288
|
type: ContentTypes.THINK,
|
|
@@ -237,82 +294,97 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
237
294
|
} else if (
|
|
238
295
|
content.every((c) => c.type?.startsWith(ContentTypes.TEXT) ?? false)
|
|
239
296
|
) {
|
|
240
|
-
graph.dispatchMessageDelta(stepId, {
|
|
297
|
+
await graph.dispatchMessageDelta(stepId, {
|
|
241
298
|
content,
|
|
242
299
|
});
|
|
243
300
|
} else if (
|
|
244
301
|
content.every(
|
|
245
302
|
(c) =>
|
|
246
303
|
(c.type?.startsWith(ContentTypes.THINKING) ?? false) ||
|
|
304
|
+
(c.type?.startsWith(ContentTypes.REASONING) ?? false) ||
|
|
247
305
|
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false)
|
|
248
306
|
)
|
|
249
307
|
) {
|
|
250
|
-
graph.dispatchReasoningDelta(stepId, {
|
|
308
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
251
309
|
content: content.map((c) => ({
|
|
252
310
|
type: ContentTypes.THINK,
|
|
253
311
|
think:
|
|
254
312
|
(c as t.ThinkingContentText).thinking ??
|
|
313
|
+
(c as Partial<t.GoogleReasoningContentText>).reasoning ??
|
|
255
314
|
(c as Partial<t.BedrockReasoningContentText>).reasoningText?.text ??
|
|
256
315
|
'',
|
|
257
316
|
})),
|
|
258
317
|
});
|
|
259
318
|
}
|
|
260
319
|
}
|
|
261
|
-
handleReasoning(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
320
|
+
handleReasoning(
|
|
321
|
+
chunk: Partial<AIMessageChunk>,
|
|
322
|
+
agentContext: AgentContext
|
|
323
|
+
): void {
|
|
324
|
+
let reasoning_content = chunk.additional_kwargs?.[
|
|
325
|
+
agentContext.reasoningKey
|
|
326
|
+
] as string | Partial<ChatOpenAIReasoningSummary> | undefined;
|
|
265
327
|
if (
|
|
266
328
|
Array.isArray(chunk.content) &&
|
|
267
|
-
(chunk.content[0]?.type ===
|
|
268
|
-
chunk.content[0]?.type ===
|
|
329
|
+
(chunk.content[0]?.type === ContentTypes.THINKING ||
|
|
330
|
+
chunk.content[0]?.type === ContentTypes.REASONING ||
|
|
331
|
+
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT)
|
|
332
|
+
) {
|
|
333
|
+
reasoning_content = 'valid';
|
|
334
|
+
} else if (
|
|
335
|
+
(agentContext.provider === Providers.OPENAI ||
|
|
336
|
+
agentContext.provider === Providers.AZURE) &&
|
|
337
|
+
reasoning_content != null &&
|
|
338
|
+
typeof reasoning_content !== 'string' &&
|
|
339
|
+
reasoning_content.summary?.[0]?.text != null &&
|
|
340
|
+
reasoning_content.summary[0].text
|
|
269
341
|
) {
|
|
270
342
|
reasoning_content = 'valid';
|
|
271
343
|
}
|
|
272
344
|
if (
|
|
273
345
|
reasoning_content != null &&
|
|
274
|
-
reasoning_content &&
|
|
346
|
+
reasoning_content !== '' &&
|
|
275
347
|
(chunk.content == null ||
|
|
276
348
|
chunk.content === '' ||
|
|
277
349
|
reasoning_content === 'valid')
|
|
278
350
|
) {
|
|
279
|
-
|
|
280
|
-
|
|
351
|
+
agentContext.currentTokenType = ContentTypes.THINK;
|
|
352
|
+
agentContext.tokenTypeSwitch = 'reasoning';
|
|
281
353
|
return;
|
|
282
354
|
} else if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
chunk.content != null &&
|
|
286
|
-
|
|
355
|
+
agentContext.tokenTypeSwitch === 'reasoning' &&
|
|
356
|
+
agentContext.currentTokenType !== ContentTypes.TEXT &&
|
|
357
|
+
((chunk.content != null && chunk.content !== '') ||
|
|
358
|
+
(chunk.tool_calls?.length ?? 0) > 0)
|
|
287
359
|
) {
|
|
288
|
-
|
|
289
|
-
|
|
360
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
361
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
290
362
|
} else if (
|
|
291
363
|
chunk.content != null &&
|
|
292
364
|
typeof chunk.content === 'string' &&
|
|
293
365
|
chunk.content.includes('<think>') &&
|
|
294
366
|
chunk.content.includes('</think>')
|
|
295
367
|
) {
|
|
296
|
-
|
|
297
|
-
|
|
368
|
+
agentContext.currentTokenType = 'think_and_text';
|
|
369
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
298
370
|
} else if (
|
|
299
371
|
chunk.content != null &&
|
|
300
372
|
typeof chunk.content === 'string' &&
|
|
301
373
|
chunk.content.includes('<think>')
|
|
302
374
|
) {
|
|
303
|
-
|
|
304
|
-
|
|
375
|
+
agentContext.currentTokenType = ContentTypes.THINK;
|
|
376
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
305
377
|
} else if (
|
|
306
|
-
|
|
307
|
-
|
|
378
|
+
agentContext.lastToken != null &&
|
|
379
|
+
agentContext.lastToken.includes('</think>')
|
|
308
380
|
) {
|
|
309
|
-
|
|
310
|
-
|
|
381
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
382
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
311
383
|
}
|
|
312
384
|
if (typeof chunk.content !== 'string') {
|
|
313
385
|
return;
|
|
314
386
|
}
|
|
315
|
-
|
|
387
|
+
agentContext.lastToken = chunk.content;
|
|
316
388
|
}
|
|
317
389
|
}
|
|
318
390
|
|
|
@@ -402,12 +474,19 @@ export function createContentAggregator(): t.ContentAggregatorResult {
|
|
|
402
474
|
|
|
403
475
|
const toolCallArgs = (contentPart.tool_call as t.ToolCallPart).args;
|
|
404
476
|
/** When args are a valid object, they are likely already invoked */
|
|
405
|
-
|
|
477
|
+
let args =
|
|
406
478
|
finalUpdate ||
|
|
407
479
|
typeof existingContent?.tool_call?.args === 'object' ||
|
|
408
480
|
typeof toolCallArgs === 'object'
|
|
409
481
|
? contentPart.tool_call.args
|
|
410
482
|
: (existingContent?.tool_call?.args ?? '') + (toolCallArgs ?? '');
|
|
483
|
+
if (
|
|
484
|
+
finalUpdate &&
|
|
485
|
+
args == null &&
|
|
486
|
+
existingContent?.tool_call?.args != null
|
|
487
|
+
) {
|
|
488
|
+
args = existingContent.tool_call.args;
|
|
489
|
+
}
|
|
411
490
|
|
|
412
491
|
const id =
|
|
413
492
|
getNonEmptyValue([
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -13,7 +13,6 @@ import type { BaseMessage, AIMessage } from '@langchain/core/messages';
|
|
|
13
13
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
14
14
|
import type * as t from '@/types';
|
|
15
15
|
import { RunnableCallable } from '@/utils';
|
|
16
|
-
import { GraphNodeKeys } from '@/common';
|
|
17
16
|
|
|
18
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
18
|
export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
@@ -138,18 +137,33 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
138
137
|
}
|
|
139
138
|
}
|
|
140
139
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
function areToolCallsInvoked(
|
|
141
|
+
message: AIMessage,
|
|
142
|
+
invokedToolIds?: Set<string>
|
|
143
|
+
): boolean {
|
|
144
|
+
if (!invokedToolIds || invokedToolIds.size === 0) return false;
|
|
145
|
+
return (
|
|
146
|
+
message.tool_calls?.every(
|
|
147
|
+
(toolCall) => toolCall.id != null && invokedToolIds.has(toolCall.id)
|
|
148
|
+
) ?? false
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function toolsCondition<T extends string>(
|
|
153
|
+
state: BaseMessage[] | typeof MessagesAnnotation.State,
|
|
154
|
+
toolNode: T,
|
|
155
|
+
invokedToolIds?: Set<string>
|
|
156
|
+
): T | typeof END {
|
|
157
|
+
const message: AIMessage = Array.isArray(state)
|
|
145
158
|
? state[state.length - 1]
|
|
146
159
|
: state.messages[state.messages.length - 1];
|
|
147
160
|
|
|
148
161
|
if (
|
|
149
162
|
'tool_calls' in message &&
|
|
150
|
-
(
|
|
163
|
+
(message.tool_calls?.length ?? 0) > 0 &&
|
|
164
|
+
!areToolCallsInvoked(message, invokedToolIds)
|
|
151
165
|
) {
|
|
152
|
-
return
|
|
166
|
+
return toolNode;
|
|
153
167
|
} else {
|
|
154
168
|
return END;
|
|
155
169
|
}
|