illuma-agents 1.0.2 → 1.0.4
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/LICENSE +25 -21
- package/dist/cjs/agents/AgentContext.cjs +222 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -0
- package/dist/cjs/common/enum.cjs +5 -4
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +7 -5
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +328 -207
- 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.map +1 -1
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/ollama/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +35 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +3 -1
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/providers.cjs +0 -2
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +12 -1
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +123 -0
- package/dist/cjs/messages/cache.cjs.map +1 -0
- package/dist/cjs/messages/content.cjs +53 -0
- package/dist/cjs/messages/content.cjs.map +1 -0
- package/dist/cjs/messages/format.cjs +17 -29
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +119 -74
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +77 -73
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/Calculator.cjs +45 -0
- package/dist/cjs/tools/Calculator.cjs.map +1 -0
- package/dist/cjs/tools/CodeExecutor.cjs +22 -22
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +5 -3
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +20 -20
- package/dist/cjs/tools/handlers.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/handlers.cjs +70 -0
- package/dist/cjs/utils/handlers.cjs.map +1 -0
- package/dist/cjs/utils/tokens.cjs +54 -7
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +220 -0
- package/dist/esm/agents/AgentContext.mjs.map +1 -0
- package/dist/esm/common/enum.mjs +5 -4
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +7 -5
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +330 -209
- 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.map +1 -1
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/ollama/index.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +35 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +3 -1
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/providers.mjs +0 -2
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +7 -2
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +120 -0
- package/dist/esm/messages/cache.mjs.map +1 -0
- package/dist/esm/messages/content.mjs +51 -0
- package/dist/esm/messages/content.mjs.map +1 -0
- package/dist/esm/messages/format.mjs +18 -29
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +119 -74
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +77 -73
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/Calculator.mjs +24 -0
- package/dist/esm/tools/Calculator.mjs.map +1 -0
- package/dist/esm/tools/CodeExecutor.mjs +22 -22
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +5 -3
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +20 -20
- package/dist/esm/tools/handlers.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/handlers.mjs +68 -0
- package/dist/esm/utils/handlers.mjs.map +1 -0
- package/dist/esm/utils/tokens.mjs +54 -8
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +94 -0
- package/dist/types/common/enum.d.ts +7 -5
- package/dist/types/events.d.ts +3 -3
- package/dist/types/graphs/Graph.d.ts +60 -66
- package/dist/types/graphs/MultiAgentGraph.d.ts +47 -0
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/llm/openai/index.d.ts +10 -0
- package/dist/types/messages/cache.d.ts +20 -0
- package/dist/types/messages/content.d.ts +7 -0
- package/dist/types/messages/format.d.ts +1 -7
- package/dist/types/messages/index.d.ts +2 -0
- package/dist/types/messages/reducer.d.ts +9 -0
- package/dist/types/run.d.ts +16 -10
- package/dist/types/stream.d.ts +4 -3
- package/dist/types/tools/Calculator.d.ts +8 -0
- package/dist/types/tools/ToolNode.d.ts +1 -1
- package/dist/types/tools/handlers.d.ts +9 -7
- package/dist/types/tools/search/tool.d.ts +4 -4
- package/dist/types/types/graph.d.ts +124 -11
- package/dist/types/types/llm.d.ts +13 -9
- package/dist/types/types/messages.d.ts +4 -0
- package/dist/types/types/run.d.ts +46 -8
- package/dist/types/types/stream.d.ts +3 -2
- package/dist/types/utils/events.d.ts +6 -0
- package/dist/types/utils/handlers.d.ts +34 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/tokens.d.ts +24 -0
- package/package.json +162 -145
- package/src/agents/AgentContext.ts +323 -0
- package/src/common/enum.ts +177 -176
- package/src/events.ts +197 -191
- package/src/graphs/Graph.ts +1058 -846
- package/src/graphs/MultiAgentGraph.ts +598 -0
- package/src/graphs/index.ts +2 -1
- package/src/index.ts +25 -24
- package/src/llm/anthropic/index.ts +413 -413
- package/src/llm/google/index.ts +222 -222
- package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -88
- package/src/llm/ollama/index.ts +92 -92
- package/src/llm/openai/index.ts +894 -853
- package/src/llm/openai/utils/index.ts +920 -918
- package/src/llm/openrouter/index.ts +60 -60
- package/src/llm/providers.ts +55 -57
- package/src/llm/vertexai/index.ts +360 -360
- package/src/messages/cache.test.ts +461 -0
- package/src/messages/cache.ts +151 -0
- package/src/messages/content.test.ts +362 -0
- package/src/messages/content.ts +63 -0
- package/src/messages/format.ts +611 -625
- package/src/messages/formatAgentMessages.test.ts +1144 -917
- package/src/messages/index.ts +6 -4
- package/src/messages/reducer.ts +80 -0
- package/src/run.ts +447 -381
- package/src/scripts/abort.ts +157 -138
- package/src/scripts/ant_web_search.ts +158 -158
- package/src/scripts/cli.ts +172 -167
- package/src/scripts/cli2.ts +133 -125
- package/src/scripts/cli3.ts +184 -178
- package/src/scripts/cli4.ts +191 -184
- package/src/scripts/cli5.ts +191 -184
- package/src/scripts/code_exec.ts +213 -214
- package/src/scripts/code_exec_simple.ts +147 -129
- package/src/scripts/content.ts +138 -120
- package/src/scripts/handoff-test.ts +135 -0
- 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 +343 -0
- package/src/scripts/multi-agent-sequence.ts +212 -0
- package/src/scripts/multi-agent-supervisor.ts +364 -0
- package/src/scripts/multi-agent-test.ts +186 -0
- package/src/scripts/search.ts +146 -150
- package/src/scripts/simple.ts +225 -225
- package/src/scripts/stream.ts +140 -122
- 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 +222 -0
- package/src/scripts/tools.ts +153 -155
- package/src/specs/agent-handoffs.test.ts +889 -0
- package/src/specs/anthropic.simple.test.ts +320 -317
- package/src/specs/azure.simple.test.ts +325 -316
- package/src/specs/openai.simple.test.ts +311 -316
- package/src/specs/openrouter.simple.test.ts +107 -0
- package/src/specs/prune.test.ts +758 -763
- package/src/specs/reasoning.test.ts +201 -165
- package/src/specs/thinking-prune.test.ts +769 -703
- package/src/specs/token-memoization.test.ts +39 -0
- package/src/stream.ts +664 -651
- package/src/tools/Calculator.test.ts +278 -0
- package/src/tools/Calculator.ts +25 -0
- package/src/tools/CodeExecutor.ts +220 -220
- package/src/tools/ToolNode.ts +170 -170
- package/src/tools/handlers.ts +341 -336
- package/src/types/graph.ts +372 -185
- package/src/types/llm.ts +141 -140
- package/src/types/messages.ts +4 -0
- package/src/types/run.ts +128 -89
- package/src/types/stream.ts +401 -400
- package/src/utils/events.ts +32 -0
- package/src/utils/handlers.ts +107 -0
- package/src/utils/index.ts +6 -5
- package/src/utils/llmConfig.ts +183 -183
- package/src/utils/tokens.ts +129 -70
- package/dist/types/scripts/abort.d.ts +0 -1
- package/dist/types/scripts/ant_web_search.d.ts +0 -1
- package/dist/types/scripts/args.d.ts +0 -7
- 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
- package/dist/types/tools/example.d.ts +0 -78
- package/src/tools/example.ts +0 -129
|
@@ -1,413 +1,413 @@
|
|
|
1
|
-
import { AIMessageChunk } from '@langchain/core/messages';
|
|
2
|
-
import { ChatAnthropicMessages } from '@langchain/anthropic';
|
|
3
|
-
import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
4
|
-
import type { BaseChatModelParams } from '@langchain/core/language_models/chat_models';
|
|
5
|
-
import type {
|
|
6
|
-
BaseMessage,
|
|
7
|
-
UsageMetadata,
|
|
8
|
-
MessageContentComplex,
|
|
9
|
-
} from '@langchain/core/messages';
|
|
10
|
-
import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
|
|
11
|
-
import type { AnthropicInput } from '@langchain/anthropic';
|
|
12
|
-
import type { Anthropic } from '@anthropic-ai/sdk';
|
|
13
|
-
import type {
|
|
14
|
-
AnthropicMessageCreateParams,
|
|
15
|
-
AnthropicStreamingMessageCreateParams,
|
|
16
|
-
AnthropicStreamUsage,
|
|
17
|
-
AnthropicMessageStartEvent,
|
|
18
|
-
AnthropicMessageDeltaEvent,
|
|
19
|
-
} from '@/llm/anthropic/types';
|
|
20
|
-
import { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';
|
|
21
|
-
import { _convertMessagesToAnthropicPayload } from './utils/message_inputs';
|
|
22
|
-
import { handleToolChoice } from './utils/tools';
|
|
23
|
-
import { TextStream } from '@/llm/text';
|
|
24
|
-
|
|
25
|
-
function _toolsInParams(
|
|
26
|
-
params: AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams
|
|
27
|
-
): boolean {
|
|
28
|
-
return !!(params.tools && params.tools.length > 0);
|
|
29
|
-
}
|
|
30
|
-
function _documentsInParams(
|
|
31
|
-
params: AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams
|
|
32
|
-
): boolean {
|
|
33
|
-
for (const message of params.messages ?? []) {
|
|
34
|
-
if (typeof message.content === 'string') {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
for (const block of message.content ?? []) {
|
|
38
|
-
if (
|
|
39
|
-
typeof block === 'object' &&
|
|
40
|
-
block != null &&
|
|
41
|
-
block.type === 'document' &&
|
|
42
|
-
typeof block.citations === 'object' &&
|
|
43
|
-
block.citations.enabled
|
|
44
|
-
) {
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function _thinkingInParams(
|
|
53
|
-
params: AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams
|
|
54
|
-
): boolean {
|
|
55
|
-
return !!(params.thinking && params.thinking.type === 'enabled');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function extractToken(
|
|
59
|
-
chunk: AIMessageChunk
|
|
60
|
-
): [string, 'string' | 'input' | 'content'] | [undefined] {
|
|
61
|
-
if (typeof chunk.content === 'string') {
|
|
62
|
-
return [chunk.content, 'string'];
|
|
63
|
-
} else if (
|
|
64
|
-
Array.isArray(chunk.content) &&
|
|
65
|
-
chunk.content.length >= 1 &&
|
|
66
|
-
'input' in chunk.content[0]
|
|
67
|
-
) {
|
|
68
|
-
return typeof chunk.content[0].input === 'string'
|
|
69
|
-
? [chunk.content[0].input, 'input']
|
|
70
|
-
: [JSON.stringify(chunk.content[0].input), 'input'];
|
|
71
|
-
} else if (
|
|
72
|
-
Array.isArray(chunk.content) &&
|
|
73
|
-
chunk.content.length >= 1 &&
|
|
74
|
-
'text' in chunk.content[0]
|
|
75
|
-
) {
|
|
76
|
-
return [chunk.content[0].text, 'content'];
|
|
77
|
-
} else if (
|
|
78
|
-
Array.isArray(chunk.content) &&
|
|
79
|
-
chunk.content.length >= 1 &&
|
|
80
|
-
'thinking' in chunk.content[0]
|
|
81
|
-
) {
|
|
82
|
-
return [chunk.content[0].thinking, 'content'];
|
|
83
|
-
}
|
|
84
|
-
return [undefined];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function cloneChunk(
|
|
88
|
-
text: string,
|
|
89
|
-
tokenType: string,
|
|
90
|
-
chunk: AIMessageChunk
|
|
91
|
-
): AIMessageChunk {
|
|
92
|
-
if (tokenType === 'string') {
|
|
93
|
-
return new AIMessageChunk(Object.assign({}, chunk, { content: text }));
|
|
94
|
-
} else if (tokenType === 'input') {
|
|
95
|
-
return chunk;
|
|
96
|
-
}
|
|
97
|
-
const content = chunk.content[0] as MessageContentComplex;
|
|
98
|
-
if (tokenType === 'content' && content.type === 'text') {
|
|
99
|
-
return new AIMessageChunk(
|
|
100
|
-
Object.assign({}, chunk, {
|
|
101
|
-
content: [Object.assign({}, content, { text })],
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
} else if (tokenType === 'content' && content.type === 'text_delta') {
|
|
105
|
-
return new AIMessageChunk(
|
|
106
|
-
Object.assign({}, chunk, {
|
|
107
|
-
content: [Object.assign({}, content, { text })],
|
|
108
|
-
})
|
|
109
|
-
);
|
|
110
|
-
} else if (tokenType === 'content' && content.type?.startsWith('thinking')) {
|
|
111
|
-
return new AIMessageChunk(
|
|
112
|
-
Object.assign({}, chunk, {
|
|
113
|
-
content: [Object.assign({}, content, { thinking: text })],
|
|
114
|
-
})
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return chunk;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export type CustomAnthropicInput = AnthropicInput & {
|
|
122
|
-
_lc_stream_delay?: number;
|
|
123
|
-
} & BaseChatModelParams;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* A type representing additional parameters that can be passed to the
|
|
127
|
-
* Anthropic API.
|
|
128
|
-
*/
|
|
129
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
|
-
type Kwargs = Record<string, any>;
|
|
131
|
-
|
|
132
|
-
export class CustomAnthropic extends ChatAnthropicMessages {
|
|
133
|
-
_lc_stream_delay: number;
|
|
134
|
-
private message_start: AnthropicMessageStartEvent | undefined;
|
|
135
|
-
private message_delta: AnthropicMessageDeltaEvent | undefined;
|
|
136
|
-
private tools_in_params?: boolean;
|
|
137
|
-
private emitted_usage?: boolean;
|
|
138
|
-
top_k: number | undefined;
|
|
139
|
-
constructor(fields?: CustomAnthropicInput) {
|
|
140
|
-
super(fields);
|
|
141
|
-
this.resetTokenEvents();
|
|
142
|
-
this.setDirectFields(fields);
|
|
143
|
-
this._lc_stream_delay = fields?._lc_stream_delay ?? 25;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
static lc_name(): 'IllumaAnthropic' {
|
|
147
|
-
return 'IllumaAnthropic';
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Get the parameters used to invoke the model
|
|
152
|
-
*/
|
|
153
|
-
override invocationParams(
|
|
154
|
-
options?: this['ParsedCallOptions']
|
|
155
|
-
): Omit<
|
|
156
|
-
AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams,
|
|
157
|
-
'messages'
|
|
158
|
-
> &
|
|
159
|
-
Kwargs {
|
|
160
|
-
const tool_choice:
|
|
161
|
-
| Anthropic.Messages.ToolChoiceAuto
|
|
162
|
-
| Anthropic.Messages.ToolChoiceAny
|
|
163
|
-
| Anthropic.Messages.ToolChoiceTool
|
|
164
|
-
| undefined = handleToolChoice(options?.tool_choice);
|
|
165
|
-
|
|
166
|
-
if (this.thinking.type === 'enabled') {
|
|
167
|
-
if (this.top_k !== -1 && (this.top_k as number | undefined) != null) {
|
|
168
|
-
throw new Error('topK is not supported when thinking is enabled');
|
|
169
|
-
}
|
|
170
|
-
if (this.topP !== -1 && (this.topP as number | undefined) != null) {
|
|
171
|
-
throw new Error('topP is not supported when thinking is enabled');
|
|
172
|
-
}
|
|
173
|
-
if (
|
|
174
|
-
this.temperature !== 1 &&
|
|
175
|
-
(this.temperature as number | undefined) != null
|
|
176
|
-
) {
|
|
177
|
-
throw new Error(
|
|
178
|
-
'temperature is not supported when thinking is enabled'
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return {
|
|
183
|
-
model: this.model,
|
|
184
|
-
stop_sequences: options?.stop ?? this.stopSequences,
|
|
185
|
-
stream: this.streaming,
|
|
186
|
-
max_tokens: this.maxTokens,
|
|
187
|
-
tools: this.formatStructuredToolToAnthropic(options?.tools),
|
|
188
|
-
tool_choice,
|
|
189
|
-
thinking: this.thinking,
|
|
190
|
-
...this.invocationKwargs,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
model: this.model,
|
|
195
|
-
temperature: this.temperature,
|
|
196
|
-
top_k: this.top_k,
|
|
197
|
-
top_p: this.topP,
|
|
198
|
-
stop_sequences: options?.stop ?? this.stopSequences,
|
|
199
|
-
stream: this.streaming,
|
|
200
|
-
max_tokens: this.maxTokens,
|
|
201
|
-
tools: this.formatStructuredToolToAnthropic(options?.tools),
|
|
202
|
-
tool_choice,
|
|
203
|
-
thinking: this.thinking,
|
|
204
|
-
...this.invocationKwargs,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Get stream usage as returned by this client's API response.
|
|
210
|
-
* @returns The stream usage object.
|
|
211
|
-
*/
|
|
212
|
-
getStreamUsage(): UsageMetadata | undefined {
|
|
213
|
-
if (this.emitted_usage === true) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
const inputUsage = this.message_start?.message.usage as
|
|
217
|
-
| undefined
|
|
218
|
-
| AnthropicStreamUsage;
|
|
219
|
-
const outputUsage = this.message_delta?.usage as
|
|
220
|
-
| undefined
|
|
221
|
-
| Partial<AnthropicStreamUsage>;
|
|
222
|
-
if (!outputUsage) {
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const totalUsage: UsageMetadata = {
|
|
226
|
-
input_tokens: inputUsage?.input_tokens ?? 0,
|
|
227
|
-
output_tokens: outputUsage.output_tokens ?? 0,
|
|
228
|
-
total_tokens:
|
|
229
|
-
(inputUsage?.input_tokens ?? 0) + (outputUsage.output_tokens ?? 0),
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
inputUsage?.cache_creation_input_tokens != null ||
|
|
234
|
-
inputUsage?.cache_read_input_tokens != null
|
|
235
|
-
) {
|
|
236
|
-
totalUsage.input_token_details = {
|
|
237
|
-
cache_creation: inputUsage.cache_creation_input_tokens ?? 0,
|
|
238
|
-
cache_read: inputUsage.cache_read_input_tokens ?? 0,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
this.emitted_usage = true;
|
|
243
|
-
return totalUsage;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
resetTokenEvents(): void {
|
|
247
|
-
this.message_start = undefined;
|
|
248
|
-
this.message_delta = undefined;
|
|
249
|
-
this.emitted_usage = undefined;
|
|
250
|
-
this.tools_in_params = undefined;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
setDirectFields(fields?: CustomAnthropicInput): void {
|
|
254
|
-
this.temperature = fields?.temperature ?? undefined;
|
|
255
|
-
this.topP = fields?.topP ?? undefined;
|
|
256
|
-
this.top_k = fields?.topK;
|
|
257
|
-
if (this.temperature === -1 || this.temperature === 1) {
|
|
258
|
-
this.temperature = undefined;
|
|
259
|
-
}
|
|
260
|
-
if (this.topP === -1) {
|
|
261
|
-
this.topP = undefined;
|
|
262
|
-
}
|
|
263
|
-
if (this.top_k === -1) {
|
|
264
|
-
this.top_k = undefined;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
private createGenerationChunk({
|
|
269
|
-
token,
|
|
270
|
-
chunk,
|
|
271
|
-
usageMetadata,
|
|
272
|
-
shouldStreamUsage,
|
|
273
|
-
}: {
|
|
274
|
-
token?: string;
|
|
275
|
-
chunk: AIMessageChunk;
|
|
276
|
-
shouldStreamUsage: boolean;
|
|
277
|
-
usageMetadata?: UsageMetadata;
|
|
278
|
-
}): ChatGenerationChunk {
|
|
279
|
-
const usage_metadata = shouldStreamUsage
|
|
280
|
-
? (usageMetadata ?? chunk.usage_metadata)
|
|
281
|
-
: undefined;
|
|
282
|
-
return new ChatGenerationChunk({
|
|
283
|
-
message: new AIMessageChunk({
|
|
284
|
-
// Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().
|
|
285
|
-
content: chunk.content,
|
|
286
|
-
additional_kwargs: chunk.additional_kwargs,
|
|
287
|
-
tool_call_chunks: chunk.tool_call_chunks,
|
|
288
|
-
response_metadata: chunk.response_metadata,
|
|
289
|
-
usage_metadata,
|
|
290
|
-
id: chunk.id,
|
|
291
|
-
}),
|
|
292
|
-
text: token ?? '',
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
async *_streamResponseChunks(
|
|
297
|
-
messages: BaseMessage[],
|
|
298
|
-
options: this['ParsedCallOptions'],
|
|
299
|
-
runManager?: CallbackManagerForLLMRun
|
|
300
|
-
): AsyncGenerator<ChatGenerationChunk> {
|
|
301
|
-
this.resetTokenEvents();
|
|
302
|
-
const params = this.invocationParams(options);
|
|
303
|
-
const formattedMessages = _convertMessagesToAnthropicPayload(messages);
|
|
304
|
-
const payload = {
|
|
305
|
-
...params,
|
|
306
|
-
...formattedMessages,
|
|
307
|
-
stream: true,
|
|
308
|
-
} as const;
|
|
309
|
-
const coerceContentToString =
|
|
310
|
-
!_toolsInParams(payload) &&
|
|
311
|
-
!_documentsInParams(payload) &&
|
|
312
|
-
!_thinkingInParams(payload);
|
|
313
|
-
|
|
314
|
-
const stream = await this.createStreamWithRetry(payload, {
|
|
315
|
-
headers: options.headers,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
|
|
319
|
-
|
|
320
|
-
for await (const data of stream) {
|
|
321
|
-
if (options.signal?.aborted === true) {
|
|
322
|
-
stream.controller.abort();
|
|
323
|
-
throw new Error('AbortError: User aborted the request.');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (data.type === 'message_start') {
|
|
327
|
-
this.message_start = data as AnthropicMessageStartEvent;
|
|
328
|
-
} else if (data.type === 'message_delta') {
|
|
329
|
-
this.message_delta = data as AnthropicMessageDeltaEvent;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
let usageMetadata: UsageMetadata | undefined;
|
|
333
|
-
if (this.tools_in_params !== true && this.emitted_usage !== true) {
|
|
334
|
-
usageMetadata = this.getStreamUsage();
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const result = _makeMessageChunkFromAnthropicEvent(data, {
|
|
338
|
-
streamUsage: shouldStreamUsage,
|
|
339
|
-
coerceContentToString,
|
|
340
|
-
});
|
|
341
|
-
if (!result) continue;
|
|
342
|
-
|
|
343
|
-
const { chunk } = result;
|
|
344
|
-
const [token = '', tokenType] = extractToken(chunk);
|
|
345
|
-
|
|
346
|
-
if (
|
|
347
|
-
!tokenType ||
|
|
348
|
-
tokenType === 'input' ||
|
|
349
|
-
(token === '' && (usageMetadata != null || chunk.id != null))
|
|
350
|
-
) {
|
|
351
|
-
const generationChunk = this.createGenerationChunk({
|
|
352
|
-
token,
|
|
353
|
-
chunk,
|
|
354
|
-
usageMetadata,
|
|
355
|
-
shouldStreamUsage,
|
|
356
|
-
});
|
|
357
|
-
yield generationChunk;
|
|
358
|
-
await runManager?.handleLLMNewToken(
|
|
359
|
-
token,
|
|
360
|
-
undefined,
|
|
361
|
-
undefined,
|
|
362
|
-
undefined,
|
|
363
|
-
undefined,
|
|
364
|
-
{ chunk: generationChunk }
|
|
365
|
-
);
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const textStream = new TextStream(token, {
|
|
370
|
-
delay: this._lc_stream_delay,
|
|
371
|
-
firstWordChunk: true,
|
|
372
|
-
minChunkSize: 4,
|
|
373
|
-
maxChunkSize: 8,
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
const generator = textStream.generateText(options.signal);
|
|
377
|
-
try {
|
|
378
|
-
let emittedUsage = false;
|
|
379
|
-
for await (const currentToken of generator) {
|
|
380
|
-
if ((options.signal as AbortSignal | undefined)?.aborted === true) {
|
|
381
|
-
break;
|
|
382
|
-
}
|
|
383
|
-
const newChunk = cloneChunk(currentToken, tokenType, chunk);
|
|
384
|
-
|
|
385
|
-
const generationChunk = this.createGenerationChunk({
|
|
386
|
-
token: currentToken,
|
|
387
|
-
chunk: newChunk,
|
|
388
|
-
usageMetadata: emittedUsage ? undefined : usageMetadata,
|
|
389
|
-
shouldStreamUsage,
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
if (usageMetadata && !emittedUsage) {
|
|
393
|
-
emittedUsage = true;
|
|
394
|
-
}
|
|
395
|
-
yield generationChunk;
|
|
396
|
-
|
|
397
|
-
await runManager?.handleLLMNewToken(
|
|
398
|
-
currentToken,
|
|
399
|
-
undefined,
|
|
400
|
-
undefined,
|
|
401
|
-
undefined,
|
|
402
|
-
undefined,
|
|
403
|
-
{ chunk: generationChunk }
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
} finally {
|
|
407
|
-
await generator.return();
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
this.resetTokenEvents();
|
|
412
|
-
}
|
|
413
|
-
}
|
|
1
|
+
import { AIMessageChunk } from '@langchain/core/messages';
|
|
2
|
+
import { ChatAnthropicMessages } from '@langchain/anthropic';
|
|
3
|
+
import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
4
|
+
import type { BaseChatModelParams } from '@langchain/core/language_models/chat_models';
|
|
5
|
+
import type {
|
|
6
|
+
BaseMessage,
|
|
7
|
+
UsageMetadata,
|
|
8
|
+
MessageContentComplex,
|
|
9
|
+
} from '@langchain/core/messages';
|
|
10
|
+
import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
|
|
11
|
+
import type { AnthropicInput } from '@langchain/anthropic';
|
|
12
|
+
import type { Anthropic } from '@anthropic-ai/sdk';
|
|
13
|
+
import type {
|
|
14
|
+
AnthropicMessageCreateParams,
|
|
15
|
+
AnthropicStreamingMessageCreateParams,
|
|
16
|
+
AnthropicStreamUsage,
|
|
17
|
+
AnthropicMessageStartEvent,
|
|
18
|
+
AnthropicMessageDeltaEvent,
|
|
19
|
+
} from '@/llm/anthropic/types';
|
|
20
|
+
import { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs';
|
|
21
|
+
import { _convertMessagesToAnthropicPayload } from './utils/message_inputs';
|
|
22
|
+
import { handleToolChoice } from './utils/tools';
|
|
23
|
+
import { TextStream } from '@/llm/text';
|
|
24
|
+
|
|
25
|
+
function _toolsInParams(
|
|
26
|
+
params: AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams
|
|
27
|
+
): boolean {
|
|
28
|
+
return !!(params.tools && params.tools.length > 0);
|
|
29
|
+
}
|
|
30
|
+
function _documentsInParams(
|
|
31
|
+
params: AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams
|
|
32
|
+
): boolean {
|
|
33
|
+
for (const message of params.messages ?? []) {
|
|
34
|
+
if (typeof message.content === 'string') {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
for (const block of message.content ?? []) {
|
|
38
|
+
if (
|
|
39
|
+
typeof block === 'object' &&
|
|
40
|
+
block != null &&
|
|
41
|
+
block.type === 'document' &&
|
|
42
|
+
typeof block.citations === 'object' &&
|
|
43
|
+
block.citations.enabled
|
|
44
|
+
) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function _thinkingInParams(
|
|
53
|
+
params: AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams
|
|
54
|
+
): boolean {
|
|
55
|
+
return !!(params.thinking && params.thinking.type === 'enabled');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function extractToken(
|
|
59
|
+
chunk: AIMessageChunk
|
|
60
|
+
): [string, 'string' | 'input' | 'content'] | [undefined] {
|
|
61
|
+
if (typeof chunk.content === 'string') {
|
|
62
|
+
return [chunk.content, 'string'];
|
|
63
|
+
} else if (
|
|
64
|
+
Array.isArray(chunk.content) &&
|
|
65
|
+
chunk.content.length >= 1 &&
|
|
66
|
+
'input' in chunk.content[0]
|
|
67
|
+
) {
|
|
68
|
+
return typeof chunk.content[0].input === 'string'
|
|
69
|
+
? [chunk.content[0].input, 'input']
|
|
70
|
+
: [JSON.stringify(chunk.content[0].input), 'input'];
|
|
71
|
+
} else if (
|
|
72
|
+
Array.isArray(chunk.content) &&
|
|
73
|
+
chunk.content.length >= 1 &&
|
|
74
|
+
'text' in chunk.content[0]
|
|
75
|
+
) {
|
|
76
|
+
return [chunk.content[0].text, 'content'];
|
|
77
|
+
} else if (
|
|
78
|
+
Array.isArray(chunk.content) &&
|
|
79
|
+
chunk.content.length >= 1 &&
|
|
80
|
+
'thinking' in chunk.content[0]
|
|
81
|
+
) {
|
|
82
|
+
return [chunk.content[0].thinking, 'content'];
|
|
83
|
+
}
|
|
84
|
+
return [undefined];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function cloneChunk(
|
|
88
|
+
text: string,
|
|
89
|
+
tokenType: string,
|
|
90
|
+
chunk: AIMessageChunk
|
|
91
|
+
): AIMessageChunk {
|
|
92
|
+
if (tokenType === 'string') {
|
|
93
|
+
return new AIMessageChunk(Object.assign({}, chunk, { content: text }));
|
|
94
|
+
} else if (tokenType === 'input') {
|
|
95
|
+
return chunk;
|
|
96
|
+
}
|
|
97
|
+
const content = chunk.content[0] as MessageContentComplex;
|
|
98
|
+
if (tokenType === 'content' && content.type === 'text') {
|
|
99
|
+
return new AIMessageChunk(
|
|
100
|
+
Object.assign({}, chunk, {
|
|
101
|
+
content: [Object.assign({}, content, { text })],
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
} else if (tokenType === 'content' && content.type === 'text_delta') {
|
|
105
|
+
return new AIMessageChunk(
|
|
106
|
+
Object.assign({}, chunk, {
|
|
107
|
+
content: [Object.assign({}, content, { text })],
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
} else if (tokenType === 'content' && content.type?.startsWith('thinking')) {
|
|
111
|
+
return new AIMessageChunk(
|
|
112
|
+
Object.assign({}, chunk, {
|
|
113
|
+
content: [Object.assign({}, content, { thinking: text })],
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return chunk;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type CustomAnthropicInput = AnthropicInput & {
|
|
122
|
+
_lc_stream_delay?: number;
|
|
123
|
+
} & BaseChatModelParams;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A type representing additional parameters that can be passed to the
|
|
127
|
+
* Anthropic API.
|
|
128
|
+
*/
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
|
+
type Kwargs = Record<string, any>;
|
|
131
|
+
|
|
132
|
+
export class CustomAnthropic extends ChatAnthropicMessages {
|
|
133
|
+
_lc_stream_delay: number;
|
|
134
|
+
private message_start: AnthropicMessageStartEvent | undefined;
|
|
135
|
+
private message_delta: AnthropicMessageDeltaEvent | undefined;
|
|
136
|
+
private tools_in_params?: boolean;
|
|
137
|
+
private emitted_usage?: boolean;
|
|
138
|
+
top_k: number | undefined;
|
|
139
|
+
constructor(fields?: CustomAnthropicInput) {
|
|
140
|
+
super(fields);
|
|
141
|
+
this.resetTokenEvents();
|
|
142
|
+
this.setDirectFields(fields);
|
|
143
|
+
this._lc_stream_delay = fields?._lc_stream_delay ?? 25;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static lc_name(): 'IllumaAnthropic' {
|
|
147
|
+
return 'IllumaAnthropic';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get the parameters used to invoke the model
|
|
152
|
+
*/
|
|
153
|
+
override invocationParams(
|
|
154
|
+
options?: this['ParsedCallOptions']
|
|
155
|
+
): Omit<
|
|
156
|
+
AnthropicMessageCreateParams | AnthropicStreamingMessageCreateParams,
|
|
157
|
+
'messages'
|
|
158
|
+
> &
|
|
159
|
+
Kwargs {
|
|
160
|
+
const tool_choice:
|
|
161
|
+
| Anthropic.Messages.ToolChoiceAuto
|
|
162
|
+
| Anthropic.Messages.ToolChoiceAny
|
|
163
|
+
| Anthropic.Messages.ToolChoiceTool
|
|
164
|
+
| undefined = handleToolChoice(options?.tool_choice);
|
|
165
|
+
|
|
166
|
+
if (this.thinking.type === 'enabled') {
|
|
167
|
+
if (this.top_k !== -1 && (this.top_k as number | undefined) != null) {
|
|
168
|
+
throw new Error('topK is not supported when thinking is enabled');
|
|
169
|
+
}
|
|
170
|
+
if (this.topP !== -1 && (this.topP as number | undefined) != null) {
|
|
171
|
+
throw new Error('topP is not supported when thinking is enabled');
|
|
172
|
+
}
|
|
173
|
+
if (
|
|
174
|
+
this.temperature !== 1 &&
|
|
175
|
+
(this.temperature as number | undefined) != null
|
|
176
|
+
) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
'temperature is not supported when thinking is enabled'
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
model: this.model,
|
|
184
|
+
stop_sequences: options?.stop ?? this.stopSequences,
|
|
185
|
+
stream: this.streaming,
|
|
186
|
+
max_tokens: this.maxTokens,
|
|
187
|
+
tools: this.formatStructuredToolToAnthropic(options?.tools),
|
|
188
|
+
tool_choice,
|
|
189
|
+
thinking: this.thinking,
|
|
190
|
+
...this.invocationKwargs,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
model: this.model,
|
|
195
|
+
temperature: this.temperature,
|
|
196
|
+
top_k: this.top_k,
|
|
197
|
+
top_p: this.topP,
|
|
198
|
+
stop_sequences: options?.stop ?? this.stopSequences,
|
|
199
|
+
stream: this.streaming,
|
|
200
|
+
max_tokens: this.maxTokens,
|
|
201
|
+
tools: this.formatStructuredToolToAnthropic(options?.tools),
|
|
202
|
+
tool_choice,
|
|
203
|
+
thinking: this.thinking,
|
|
204
|
+
...this.invocationKwargs,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get stream usage as returned by this client's API response.
|
|
210
|
+
* @returns The stream usage object.
|
|
211
|
+
*/
|
|
212
|
+
getStreamUsage(): UsageMetadata | undefined {
|
|
213
|
+
if (this.emitted_usage === true) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const inputUsage = this.message_start?.message.usage as
|
|
217
|
+
| undefined
|
|
218
|
+
| AnthropicStreamUsage;
|
|
219
|
+
const outputUsage = this.message_delta?.usage as
|
|
220
|
+
| undefined
|
|
221
|
+
| Partial<AnthropicStreamUsage>;
|
|
222
|
+
if (!outputUsage) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const totalUsage: UsageMetadata = {
|
|
226
|
+
input_tokens: inputUsage?.input_tokens ?? 0,
|
|
227
|
+
output_tokens: outputUsage.output_tokens ?? 0,
|
|
228
|
+
total_tokens:
|
|
229
|
+
(inputUsage?.input_tokens ?? 0) + (outputUsage.output_tokens ?? 0),
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
if (
|
|
233
|
+
inputUsage?.cache_creation_input_tokens != null ||
|
|
234
|
+
inputUsage?.cache_read_input_tokens != null
|
|
235
|
+
) {
|
|
236
|
+
totalUsage.input_token_details = {
|
|
237
|
+
cache_creation: inputUsage.cache_creation_input_tokens ?? 0,
|
|
238
|
+
cache_read: inputUsage.cache_read_input_tokens ?? 0,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
this.emitted_usage = true;
|
|
243
|
+
return totalUsage;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
resetTokenEvents(): void {
|
|
247
|
+
this.message_start = undefined;
|
|
248
|
+
this.message_delta = undefined;
|
|
249
|
+
this.emitted_usage = undefined;
|
|
250
|
+
this.tools_in_params = undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
setDirectFields(fields?: CustomAnthropicInput): void {
|
|
254
|
+
this.temperature = fields?.temperature ?? undefined;
|
|
255
|
+
this.topP = fields?.topP ?? undefined;
|
|
256
|
+
this.top_k = fields?.topK;
|
|
257
|
+
if (this.temperature === -1 || this.temperature === 1) {
|
|
258
|
+
this.temperature = undefined;
|
|
259
|
+
}
|
|
260
|
+
if (this.topP === -1) {
|
|
261
|
+
this.topP = undefined;
|
|
262
|
+
}
|
|
263
|
+
if (this.top_k === -1) {
|
|
264
|
+
this.top_k = undefined;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private createGenerationChunk({
|
|
269
|
+
token,
|
|
270
|
+
chunk,
|
|
271
|
+
usageMetadata,
|
|
272
|
+
shouldStreamUsage,
|
|
273
|
+
}: {
|
|
274
|
+
token?: string;
|
|
275
|
+
chunk: AIMessageChunk;
|
|
276
|
+
shouldStreamUsage: boolean;
|
|
277
|
+
usageMetadata?: UsageMetadata;
|
|
278
|
+
}): ChatGenerationChunk {
|
|
279
|
+
const usage_metadata = shouldStreamUsage
|
|
280
|
+
? (usageMetadata ?? chunk.usage_metadata)
|
|
281
|
+
: undefined;
|
|
282
|
+
return new ChatGenerationChunk({
|
|
283
|
+
message: new AIMessageChunk({
|
|
284
|
+
// Just yield chunk as it is and tool_use will be concat by BaseChatModel._generateUncached().
|
|
285
|
+
content: chunk.content,
|
|
286
|
+
additional_kwargs: chunk.additional_kwargs,
|
|
287
|
+
tool_call_chunks: chunk.tool_call_chunks,
|
|
288
|
+
response_metadata: chunk.response_metadata,
|
|
289
|
+
usage_metadata,
|
|
290
|
+
id: chunk.id,
|
|
291
|
+
}),
|
|
292
|
+
text: token ?? '',
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async *_streamResponseChunks(
|
|
297
|
+
messages: BaseMessage[],
|
|
298
|
+
options: this['ParsedCallOptions'],
|
|
299
|
+
runManager?: CallbackManagerForLLMRun
|
|
300
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
301
|
+
this.resetTokenEvents();
|
|
302
|
+
const params = this.invocationParams(options);
|
|
303
|
+
const formattedMessages = _convertMessagesToAnthropicPayload(messages);
|
|
304
|
+
const payload = {
|
|
305
|
+
...params,
|
|
306
|
+
...formattedMessages,
|
|
307
|
+
stream: true,
|
|
308
|
+
} as const;
|
|
309
|
+
const coerceContentToString =
|
|
310
|
+
!_toolsInParams(payload) &&
|
|
311
|
+
!_documentsInParams(payload) &&
|
|
312
|
+
!_thinkingInParams(payload);
|
|
313
|
+
|
|
314
|
+
const stream = await this.createStreamWithRetry(payload, {
|
|
315
|
+
headers: options.headers,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const shouldStreamUsage = this.streamUsage ?? options.streamUsage;
|
|
319
|
+
|
|
320
|
+
for await (const data of stream) {
|
|
321
|
+
if (options.signal?.aborted === true) {
|
|
322
|
+
stream.controller.abort();
|
|
323
|
+
throw new Error('AbortError: User aborted the request.');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (data.type === 'message_start') {
|
|
327
|
+
this.message_start = data as AnthropicMessageStartEvent;
|
|
328
|
+
} else if (data.type === 'message_delta') {
|
|
329
|
+
this.message_delta = data as AnthropicMessageDeltaEvent;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
let usageMetadata: UsageMetadata | undefined;
|
|
333
|
+
if (this.tools_in_params !== true && this.emitted_usage !== true) {
|
|
334
|
+
usageMetadata = this.getStreamUsage();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const result = _makeMessageChunkFromAnthropicEvent(data, {
|
|
338
|
+
streamUsage: shouldStreamUsage,
|
|
339
|
+
coerceContentToString,
|
|
340
|
+
});
|
|
341
|
+
if (!result) continue;
|
|
342
|
+
|
|
343
|
+
const { chunk } = result;
|
|
344
|
+
const [token = '', tokenType] = extractToken(chunk);
|
|
345
|
+
|
|
346
|
+
if (
|
|
347
|
+
!tokenType ||
|
|
348
|
+
tokenType === 'input' ||
|
|
349
|
+
(token === '' && (usageMetadata != null || chunk.id != null))
|
|
350
|
+
) {
|
|
351
|
+
const generationChunk = this.createGenerationChunk({
|
|
352
|
+
token,
|
|
353
|
+
chunk,
|
|
354
|
+
usageMetadata,
|
|
355
|
+
shouldStreamUsage,
|
|
356
|
+
});
|
|
357
|
+
yield generationChunk;
|
|
358
|
+
await runManager?.handleLLMNewToken(
|
|
359
|
+
token,
|
|
360
|
+
undefined,
|
|
361
|
+
undefined,
|
|
362
|
+
undefined,
|
|
363
|
+
undefined,
|
|
364
|
+
{ chunk: generationChunk }
|
|
365
|
+
);
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const textStream = new TextStream(token, {
|
|
370
|
+
delay: this._lc_stream_delay,
|
|
371
|
+
firstWordChunk: true,
|
|
372
|
+
minChunkSize: 4,
|
|
373
|
+
maxChunkSize: 8,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const generator = textStream.generateText(options.signal);
|
|
377
|
+
try {
|
|
378
|
+
let emittedUsage = false;
|
|
379
|
+
for await (const currentToken of generator) {
|
|
380
|
+
if ((options.signal as AbortSignal | undefined)?.aborted === true) {
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
const newChunk = cloneChunk(currentToken, tokenType, chunk);
|
|
384
|
+
|
|
385
|
+
const generationChunk = this.createGenerationChunk({
|
|
386
|
+
token: currentToken,
|
|
387
|
+
chunk: newChunk,
|
|
388
|
+
usageMetadata: emittedUsage ? undefined : usageMetadata,
|
|
389
|
+
shouldStreamUsage,
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
if (usageMetadata && !emittedUsage) {
|
|
393
|
+
emittedUsage = true;
|
|
394
|
+
}
|
|
395
|
+
yield generationChunk;
|
|
396
|
+
|
|
397
|
+
await runManager?.handleLLMNewToken(
|
|
398
|
+
currentToken,
|
|
399
|
+
undefined,
|
|
400
|
+
undefined,
|
|
401
|
+
undefined,
|
|
402
|
+
undefined,
|
|
403
|
+
{ chunk: generationChunk }
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
} finally {
|
|
407
|
+
await generator.return();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
this.resetTokenEvents();
|
|
412
|
+
}
|
|
413
|
+
}
|