@librechat/agents 2.4.322 → 3.0.0-rc10
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 +15 -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 -213
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +507 -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 +422 -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 +137 -85
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +86 -52
- 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 +16 -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 -215
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +505 -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 +421 -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 +138 -87
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +88 -55
- 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 +17 -7
- package/dist/types/events.d.ts +5 -4
- package/dist/types/graphs/Graph.d.ts +64 -67
- package/dist/types/graphs/MultiAgentGraph.d.ts +47 -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 +82 -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/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 +25 -10
- package/dist/types/types/run.d.ts +50 -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 +41 -17
- package/src/agents/AgentContext.ts +315 -0
- package/src/common/enum.ts +15 -5
- package/src/events.ts +24 -13
- package/src/graphs/Graph.ts +495 -313
- package/src/graphs/MultiAgentGraph.ts +598 -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 +641 -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 +196 -116
- 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-chain.ts +278 -0
- package/src/scripts/multi-agent-conditional.ts +220 -0
- package/src/scripts/multi-agent-document-review-chain.ts +197 -0
- package/src/scripts/multi-agent-hybrid-flow.ts +310 -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 +362 -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 +170 -0
- package/src/scripts/test-multi-agent-list-handoff.ts +261 -0
- package/src/scripts/test-tools-before-handoff.ts +233 -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 +143 -61
- 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 +318 -103
- package/src/types/llm.ts +26 -12
- package/src/types/run.ts +56 -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
- package/dist/types/scripts/abort.d.ts +0 -1
- package/dist/types/scripts/args.d.ts +0 -6
- package/dist/types/scripts/caching.d.ts +0 -1
- package/dist/types/scripts/cli.d.ts +0 -1
- package/dist/types/scripts/cli2.d.ts +0 -1
- package/dist/types/scripts/cli3.d.ts +0 -1
- package/dist/types/scripts/cli4.d.ts +0 -1
- package/dist/types/scripts/cli5.d.ts +0 -1
- package/dist/types/scripts/code_exec.d.ts +0 -1
- package/dist/types/scripts/code_exec_files.d.ts +0 -1
- package/dist/types/scripts/code_exec_simple.d.ts +0 -1
- package/dist/types/scripts/content.d.ts +0 -1
- package/dist/types/scripts/empty_input.d.ts +0 -1
- package/dist/types/scripts/image.d.ts +0 -1
- package/dist/types/scripts/memory.d.ts +0 -1
- package/dist/types/scripts/search.d.ts +0 -1
- package/dist/types/scripts/simple.d.ts +0 -1
- package/dist/types/scripts/stream.d.ts +0 -1
- package/dist/types/scripts/thinking.d.ts +0 -1
- package/dist/types/scripts/tools.d.ts +0 -1
- package/dist/types/specs/spec.utils.d.ts +0 -1
|
@@ -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,20 +131,35 @@ 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 &&
|
|
96
155
|
chunk.tool_calls.length > 0 &&
|
|
97
|
-
chunk.tool_calls.every(
|
|
156
|
+
chunk.tool_calls.every(
|
|
157
|
+
(tc) =>
|
|
158
|
+
tc.id != null && tc.id !== '' && tc.name != null && tc.name !== ''
|
|
159
|
+
)
|
|
98
160
|
) {
|
|
99
161
|
hasToolCalls = true;
|
|
100
|
-
handleToolCalls(chunk.tool_calls, metadata, graph);
|
|
162
|
+
await handleToolCalls(chunk.tool_calls, metadata, graph);
|
|
101
163
|
}
|
|
102
164
|
|
|
103
165
|
const hasToolCallChunks =
|
|
@@ -106,18 +168,16 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
106
168
|
typeof content === 'undefined' ||
|
|
107
169
|
!content.length ||
|
|
108
170
|
(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
171
|
|
|
172
|
+
/** Set a preliminary message ID if found in empty chunk */
|
|
173
|
+
const isEmptyChunk = isEmptyContent && !hasToolCallChunks;
|
|
174
|
+
if (
|
|
175
|
+
isEmptyChunk &&
|
|
176
|
+
(chunk.id ?? '') !== '' &&
|
|
177
|
+
!graph.prelimMessageIdsByStepKey.has(chunk.id ?? '')
|
|
178
|
+
) {
|
|
118
179
|
const stepKey = graph.getStepKey(metadata);
|
|
119
|
-
graph.prelimMessageIdsByStepKey.set(stepKey,
|
|
120
|
-
return;
|
|
180
|
+
graph.prelimMessageIdsByStepKey.set(stepKey, chunk.id ?? '');
|
|
121
181
|
} else if (isEmptyChunk) {
|
|
122
182
|
return;
|
|
123
183
|
}
|
|
@@ -130,7 +190,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
130
190
|
chunk.tool_call_chunks.length &&
|
|
131
191
|
typeof chunk.tool_call_chunks[0]?.index === 'number'
|
|
132
192
|
) {
|
|
133
|
-
handleToolCallChunks({
|
|
193
|
+
await handleToolCallChunks({
|
|
134
194
|
graph,
|
|
135
195
|
stepKey,
|
|
136
196
|
toolCallChunks: chunk.tool_call_chunks,
|
|
@@ -143,7 +203,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
143
203
|
|
|
144
204
|
const message_id = getMessageId(stepKey, graph) ?? '';
|
|
145
205
|
if (message_id) {
|
|
146
|
-
graph.dispatchRunStep(stepKey, {
|
|
206
|
+
await graph.dispatchRunStep(stepKey, {
|
|
147
207
|
type: StepTypes.MESSAGE_CREATION,
|
|
148
208
|
message_creation: {
|
|
149
209
|
message_id,
|
|
@@ -181,8 +241,8 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
181
241
|
) {
|
|
182
242
|
return;
|
|
183
243
|
} else if (typeof content === 'string') {
|
|
184
|
-
if (
|
|
185
|
-
graph.dispatchMessageDelta(stepId, {
|
|
244
|
+
if (agentContext.currentTokenType === ContentTypes.TEXT) {
|
|
245
|
+
await graph.dispatchMessageDelta(stepId, {
|
|
186
246
|
content: [
|
|
187
247
|
{
|
|
188
248
|
type: ContentTypes.TEXT,
|
|
@@ -190,10 +250,10 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
190
250
|
},
|
|
191
251
|
],
|
|
192
252
|
});
|
|
193
|
-
} else if (
|
|
253
|
+
} else if (agentContext.currentTokenType === 'think_and_text') {
|
|
194
254
|
const { text, thinking } = parseThinkingContent(content);
|
|
195
255
|
if (thinking) {
|
|
196
|
-
graph.dispatchReasoningDelta(stepId, {
|
|
256
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
197
257
|
content: [
|
|
198
258
|
{
|
|
199
259
|
type: ContentTypes.THINK,
|
|
@@ -203,11 +263,11 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
203
263
|
});
|
|
204
264
|
}
|
|
205
265
|
if (text) {
|
|
206
|
-
|
|
207
|
-
|
|
266
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
267
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
208
268
|
const newStepKey = graph.getStepKey(metadata);
|
|
209
269
|
const message_id = getMessageId(newStepKey, graph) ?? '';
|
|
210
|
-
graph.dispatchRunStep(newStepKey, {
|
|
270
|
+
await graph.dispatchRunStep(newStepKey, {
|
|
211
271
|
type: StepTypes.MESSAGE_CREATION,
|
|
212
272
|
message_creation: {
|
|
213
273
|
message_id,
|
|
@@ -215,7 +275,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
215
275
|
});
|
|
216
276
|
|
|
217
277
|
const newStepId = graph.getStepIdByKey(newStepKey);
|
|
218
|
-
graph.dispatchMessageDelta(newStepId, {
|
|
278
|
+
await graph.dispatchMessageDelta(newStepId, {
|
|
219
279
|
content: [
|
|
220
280
|
{
|
|
221
281
|
type: ContentTypes.TEXT,
|
|
@@ -225,7 +285,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
225
285
|
});
|
|
226
286
|
}
|
|
227
287
|
} else {
|
|
228
|
-
graph.dispatchReasoningDelta(stepId, {
|
|
288
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
229
289
|
content: [
|
|
230
290
|
{
|
|
231
291
|
type: ContentTypes.THINK,
|
|
@@ -237,82 +297,97 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
237
297
|
} else if (
|
|
238
298
|
content.every((c) => c.type?.startsWith(ContentTypes.TEXT) ?? false)
|
|
239
299
|
) {
|
|
240
|
-
graph.dispatchMessageDelta(stepId, {
|
|
300
|
+
await graph.dispatchMessageDelta(stepId, {
|
|
241
301
|
content,
|
|
242
302
|
});
|
|
243
303
|
} else if (
|
|
244
304
|
content.every(
|
|
245
305
|
(c) =>
|
|
246
306
|
(c.type?.startsWith(ContentTypes.THINKING) ?? false) ||
|
|
307
|
+
(c.type?.startsWith(ContentTypes.REASONING) ?? false) ||
|
|
247
308
|
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false)
|
|
248
309
|
)
|
|
249
310
|
) {
|
|
250
|
-
graph.dispatchReasoningDelta(stepId, {
|
|
311
|
+
await graph.dispatchReasoningDelta(stepId, {
|
|
251
312
|
content: content.map((c) => ({
|
|
252
313
|
type: ContentTypes.THINK,
|
|
253
314
|
think:
|
|
254
315
|
(c as t.ThinkingContentText).thinking ??
|
|
316
|
+
(c as Partial<t.GoogleReasoningContentText>).reasoning ??
|
|
255
317
|
(c as Partial<t.BedrockReasoningContentText>).reasoningText?.text ??
|
|
256
318
|
'',
|
|
257
319
|
})),
|
|
258
320
|
});
|
|
259
321
|
}
|
|
260
322
|
}
|
|
261
|
-
handleReasoning(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
323
|
+
handleReasoning(
|
|
324
|
+
chunk: Partial<AIMessageChunk>,
|
|
325
|
+
agentContext: AgentContext
|
|
326
|
+
): void {
|
|
327
|
+
let reasoning_content = chunk.additional_kwargs?.[
|
|
328
|
+
agentContext.reasoningKey
|
|
329
|
+
] as string | Partial<ChatOpenAIReasoningSummary> | undefined;
|
|
265
330
|
if (
|
|
266
331
|
Array.isArray(chunk.content) &&
|
|
267
|
-
(chunk.content[0]?.type ===
|
|
268
|
-
chunk.content[0]?.type ===
|
|
332
|
+
(chunk.content[0]?.type === ContentTypes.THINKING ||
|
|
333
|
+
chunk.content[0]?.type === ContentTypes.REASONING ||
|
|
334
|
+
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT)
|
|
335
|
+
) {
|
|
336
|
+
reasoning_content = 'valid';
|
|
337
|
+
} else if (
|
|
338
|
+
(agentContext.provider === Providers.OPENAI ||
|
|
339
|
+
agentContext.provider === Providers.AZURE) &&
|
|
340
|
+
reasoning_content != null &&
|
|
341
|
+
typeof reasoning_content !== 'string' &&
|
|
342
|
+
reasoning_content.summary?.[0]?.text != null &&
|
|
343
|
+
reasoning_content.summary[0].text
|
|
269
344
|
) {
|
|
270
345
|
reasoning_content = 'valid';
|
|
271
346
|
}
|
|
272
347
|
if (
|
|
273
348
|
reasoning_content != null &&
|
|
274
|
-
reasoning_content &&
|
|
349
|
+
reasoning_content !== '' &&
|
|
275
350
|
(chunk.content == null ||
|
|
276
351
|
chunk.content === '' ||
|
|
277
352
|
reasoning_content === 'valid')
|
|
278
353
|
) {
|
|
279
|
-
|
|
280
|
-
|
|
354
|
+
agentContext.currentTokenType = ContentTypes.THINK;
|
|
355
|
+
agentContext.tokenTypeSwitch = 'reasoning';
|
|
281
356
|
return;
|
|
282
357
|
} else if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
chunk.content != null &&
|
|
286
|
-
|
|
358
|
+
agentContext.tokenTypeSwitch === 'reasoning' &&
|
|
359
|
+
agentContext.currentTokenType !== ContentTypes.TEXT &&
|
|
360
|
+
((chunk.content != null && chunk.content !== '') ||
|
|
361
|
+
(chunk.tool_calls?.length ?? 0) > 0)
|
|
287
362
|
) {
|
|
288
|
-
|
|
289
|
-
|
|
363
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
364
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
290
365
|
} else if (
|
|
291
366
|
chunk.content != null &&
|
|
292
367
|
typeof chunk.content === 'string' &&
|
|
293
368
|
chunk.content.includes('<think>') &&
|
|
294
369
|
chunk.content.includes('</think>')
|
|
295
370
|
) {
|
|
296
|
-
|
|
297
|
-
|
|
371
|
+
agentContext.currentTokenType = 'think_and_text';
|
|
372
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
298
373
|
} else if (
|
|
299
374
|
chunk.content != null &&
|
|
300
375
|
typeof chunk.content === 'string' &&
|
|
301
376
|
chunk.content.includes('<think>')
|
|
302
377
|
) {
|
|
303
|
-
|
|
304
|
-
|
|
378
|
+
agentContext.currentTokenType = ContentTypes.THINK;
|
|
379
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
305
380
|
} else if (
|
|
306
|
-
|
|
307
|
-
|
|
381
|
+
agentContext.lastToken != null &&
|
|
382
|
+
agentContext.lastToken.includes('</think>')
|
|
308
383
|
) {
|
|
309
|
-
|
|
310
|
-
|
|
384
|
+
agentContext.currentTokenType = ContentTypes.TEXT;
|
|
385
|
+
agentContext.tokenTypeSwitch = 'content';
|
|
311
386
|
}
|
|
312
387
|
if (typeof chunk.content !== 'string') {
|
|
313
388
|
return;
|
|
314
389
|
}
|
|
315
|
-
|
|
390
|
+
agentContext.lastToken = chunk.content;
|
|
316
391
|
}
|
|
317
392
|
}
|
|
318
393
|
|
|
@@ -402,12 +477,19 @@ export function createContentAggregator(): t.ContentAggregatorResult {
|
|
|
402
477
|
|
|
403
478
|
const toolCallArgs = (contentPart.tool_call as t.ToolCallPart).args;
|
|
404
479
|
/** When args are a valid object, they are likely already invoked */
|
|
405
|
-
|
|
480
|
+
let args =
|
|
406
481
|
finalUpdate ||
|
|
407
482
|
typeof existingContent?.tool_call?.args === 'object' ||
|
|
408
483
|
typeof toolCallArgs === 'object'
|
|
409
484
|
? contentPart.tool_call.args
|
|
410
485
|
: (existingContent?.tool_call?.args ?? '') + (toolCallArgs ?? '');
|
|
486
|
+
if (
|
|
487
|
+
finalUpdate &&
|
|
488
|
+
args == null &&
|
|
489
|
+
existingContent?.tool_call?.args != null
|
|
490
|
+
) {
|
|
491
|
+
args = existingContent.tool_call.args;
|
|
492
|
+
}
|
|
411
493
|
|
|
412
494
|
const id =
|
|
413
495
|
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
|
}
|