@namzu/sdk 0.1.6 → 0.1.8
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/CHANGELOG.md +31 -0
- package/README.md +14 -9
- package/dist/constants/provider/index.d.ts +0 -3
- package/dist/constants/provider/index.d.ts.map +1 -1
- package/dist/constants/provider/index.js +0 -18
- package/dist/constants/provider/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/provider/__tests__/registry.test.d.ts +11 -0
- package/dist/provider/__tests__/registry.test.d.ts.map +1 -0
- package/dist/provider/__tests__/registry.test.js +118 -0
- package/dist/provider/__tests__/registry.test.js.map +1 -0
- package/dist/provider/index.d.ts +3 -3
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +3 -3
- package/dist/provider/index.js.map +1 -1
- package/dist/provider/mock-register.d.ts +12 -0
- package/dist/provider/mock-register.d.ts.map +1 -0
- package/dist/provider/mock-register.js +24 -0
- package/dist/provider/mock-register.js.map +1 -0
- package/dist/provider/mock.d.ts +26 -0
- package/dist/provider/mock.d.ts.map +1 -0
- package/dist/provider/{factory.js → mock.js} +3 -45
- package/dist/provider/mock.js.map +1 -0
- package/dist/provider/registry.d.ts +47 -0
- package/dist/provider/registry.d.ts.map +1 -0
- package/dist/provider/registry.js +89 -0
- package/dist/provider/registry.js.map +1 -0
- package/dist/rag/rag-tool.d.ts +1 -1
- package/dist/types/provider/config.d.ts +29 -21
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/index.d.ts +1 -1
- package/dist/types/provider/index.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/constants/provider/index.ts +0 -22
- package/src/index.ts +5 -4
- package/src/provider/__tests__/registry.test.ts +155 -0
- package/src/provider/index.ts +3 -3
- package/src/provider/mock-register.ts +27 -0
- package/src/provider/{factory.ts → mock.ts} +2 -57
- package/src/provider/registry.ts +118 -0
- package/src/types/provider/config.ts +31 -29
- package/src/types/provider/index.ts +3 -4
- package/dist/provider/bedrock/client.d.ts +0 -14
- package/dist/provider/bedrock/client.d.ts.map +0 -1
- package/dist/provider/bedrock/client.js +0 -460
- package/dist/provider/bedrock/client.js.map +0 -1
- package/dist/provider/factory.d.ts +0 -39
- package/dist/provider/factory.d.ts.map +0 -1
- package/dist/provider/factory.js.map +0 -1
- package/dist/provider/openrouter/client.d.ts +0 -17
- package/dist/provider/openrouter/client.d.ts.map +0 -1
- package/dist/provider/openrouter/client.js +0 -305
- package/dist/provider/openrouter/client.js.map +0 -1
- package/src/provider/bedrock/client.ts +0 -548
- package/src/provider/openrouter/client.ts +0 -390
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BedrockRuntimeClient,
|
|
3
|
-
ConverseCommand,
|
|
4
|
-
ConverseStreamCommand,
|
|
5
|
-
} from '@aws-sdk/client-bedrock-runtime'
|
|
6
|
-
import type {
|
|
7
|
-
Message as BedrockMessage,
|
|
8
|
-
ContentBlock,
|
|
9
|
-
ConversationRole,
|
|
10
|
-
ConverseStreamOutput,
|
|
11
|
-
SystemContentBlock,
|
|
12
|
-
Tool,
|
|
13
|
-
ToolConfiguration,
|
|
14
|
-
ToolResultContentBlock,
|
|
15
|
-
ToolUseBlock,
|
|
16
|
-
} from '@aws-sdk/client-bedrock-runtime'
|
|
17
|
-
import { SpanStatusCode } from '@opentelemetry/api'
|
|
18
|
-
import { GENAI, NAMZU, chatSpanName } from '../../telemetry/attributes.js'
|
|
19
|
-
import type { TokenUsage } from '../../types/common/index.js'
|
|
20
|
-
import type {
|
|
21
|
-
ChatCompletionParams,
|
|
22
|
-
ChatCompletionResponse,
|
|
23
|
-
LLMProvider,
|
|
24
|
-
ModelInfo,
|
|
25
|
-
StreamChunk,
|
|
26
|
-
ToolChoice,
|
|
27
|
-
} from '../../types/provider/index.js'
|
|
28
|
-
import type { BedrockConfig } from '../../types/provider/index.js'
|
|
29
|
-
import { toErrorMessage } from '../../utils/error.js'
|
|
30
|
-
import { getRootLogger } from '../../utils/logger.js'
|
|
31
|
-
import { getTracer } from '../telemetry/setup.js'
|
|
32
|
-
|
|
33
|
-
const logger = getRootLogger().child({ component: 'BedrockProvider' })
|
|
34
|
-
|
|
35
|
-
function extractSystemBlocks(messages: ChatCompletionParams['messages']): SystemContentBlock[] {
|
|
36
|
-
return messages
|
|
37
|
-
.filter((m) => m.role === 'system')
|
|
38
|
-
.map((m) => ({ text: typeof m.content === 'string' ? m.content : '' }))
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function toBedrockRole(role: string): ConversationRole {
|
|
42
|
-
return role === 'assistant' ? 'assistant' : 'user'
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function toBedrockMessages(messages: ChatCompletionParams['messages']): BedrockMessage[] {
|
|
46
|
-
const out: BedrockMessage[] = []
|
|
47
|
-
|
|
48
|
-
let pendingToolResults: ContentBlock[] = []
|
|
49
|
-
|
|
50
|
-
const flushToolResults = () => {
|
|
51
|
-
if (pendingToolResults.length > 0) {
|
|
52
|
-
out.push({ role: 'user', content: pendingToolResults })
|
|
53
|
-
pendingToolResults = []
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
for (const msg of messages) {
|
|
58
|
-
if (msg.role === 'system') continue
|
|
59
|
-
|
|
60
|
-
if (msg.role === 'tool') {
|
|
61
|
-
const toolMsg = msg as { toolCallId?: string; content?: string }
|
|
62
|
-
const resultBlock: ToolResultContentBlock = {
|
|
63
|
-
text:
|
|
64
|
-
typeof toolMsg.content === 'string' ? toolMsg.content : JSON.stringify(toolMsg.content),
|
|
65
|
-
}
|
|
66
|
-
pendingToolResults.push({
|
|
67
|
-
toolResult: {
|
|
68
|
-
toolUseId: toolMsg.toolCallId ?? 'unknown',
|
|
69
|
-
content: [resultBlock],
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
continue
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
flushToolResults()
|
|
76
|
-
|
|
77
|
-
if (msg.role === 'assistant' && 'toolCalls' in msg && msg.toolCalls) {
|
|
78
|
-
const content: ContentBlock[] = []
|
|
79
|
-
if (msg.content) {
|
|
80
|
-
content.push({ text: msg.content })
|
|
81
|
-
}
|
|
82
|
-
for (const tc of msg.toolCalls) {
|
|
83
|
-
content.push({
|
|
84
|
-
toolUse: {
|
|
85
|
-
toolUseId: tc.id,
|
|
86
|
-
name: tc.function.name,
|
|
87
|
-
input: JSON.parse(tc.function.arguments || '{}'),
|
|
88
|
-
},
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
out.push({ role: 'assistant', content })
|
|
92
|
-
continue
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const text = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)
|
|
96
|
-
out.push({
|
|
97
|
-
role: toBedrockRole(msg.role),
|
|
98
|
-
content: [{ text }],
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
flushToolResults()
|
|
103
|
-
|
|
104
|
-
return out
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function messagesContainToolBlocks(messages: ChatCompletionParams['messages']): boolean {
|
|
108
|
-
for (const msg of messages) {
|
|
109
|
-
if (msg.role === 'tool') return true
|
|
110
|
-
if (
|
|
111
|
-
msg.role === 'assistant' &&
|
|
112
|
-
'toolCalls' in msg &&
|
|
113
|
-
msg.toolCalls &&
|
|
114
|
-
msg.toolCalls.length > 0
|
|
115
|
-
) {
|
|
116
|
-
return true
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return false
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function extractToolNamesFromHistory(messages: ChatCompletionParams['messages']): string[] {
|
|
123
|
-
const names = new Set<string>()
|
|
124
|
-
for (const msg of messages) {
|
|
125
|
-
if (msg.role === 'assistant' && 'toolCalls' in msg && msg.toolCalls) {
|
|
126
|
-
for (const tc of msg.toolCalls) {
|
|
127
|
-
names.add(tc.function.name)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return Array.from(names)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function toBedrockToolConfig(params: ChatCompletionParams): ToolConfiguration | undefined {
|
|
135
|
-
if (params.tools && params.tools.length > 0) {
|
|
136
|
-
const tools: Tool[] = params.tools.map(
|
|
137
|
-
(t) =>
|
|
138
|
-
({
|
|
139
|
-
toolSpec: {
|
|
140
|
-
name: t.function.name,
|
|
141
|
-
description: t.function.description ?? '',
|
|
142
|
-
inputSchema: {
|
|
143
|
-
json: (t.function.parameters ?? {}) as Record<string, unknown>,
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
}) as Tool,
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
const toolChoice = formatToolChoice(params.toolChoice)
|
|
150
|
-
return { tools, toolChoice }
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (messagesContainToolBlocks(params.messages)) {
|
|
154
|
-
const toolNames = extractToolNamesFromHistory(params.messages)
|
|
155
|
-
if (toolNames.length > 0) {
|
|
156
|
-
const tools: Tool[] = toolNames.map(
|
|
157
|
-
(name) =>
|
|
158
|
-
({
|
|
159
|
-
toolSpec: {
|
|
160
|
-
name,
|
|
161
|
-
description: '(completed)',
|
|
162
|
-
inputSchema: { json: { type: 'object' } },
|
|
163
|
-
},
|
|
164
|
-
}) as Tool,
|
|
165
|
-
)
|
|
166
|
-
return { tools, toolChoice: { auto: {} } }
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return undefined
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function formatToolChoice(tc?: ToolChoice) {
|
|
174
|
-
if (!tc || tc === 'auto') return { auto: {} }
|
|
175
|
-
if (tc === 'none') return { auto: {} }
|
|
176
|
-
if (tc === 'required') return { any: {} }
|
|
177
|
-
if (typeof tc === 'object' && tc.type === 'function') {
|
|
178
|
-
return { tool: { name: tc.function.name } }
|
|
179
|
-
}
|
|
180
|
-
return { auto: {} }
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
interface RawBedrockUsage {
|
|
184
|
-
inputTokens?: number
|
|
185
|
-
outputTokens?: number
|
|
186
|
-
totalTokens?: number
|
|
187
|
-
cacheReadInputTokenCount?: number
|
|
188
|
-
cacheWriteInputTokenCount?: number
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function parseUsage(raw?: RawBedrockUsage): TokenUsage {
|
|
192
|
-
if (!raw) {
|
|
193
|
-
return {
|
|
194
|
-
promptTokens: 0,
|
|
195
|
-
completionTokens: 0,
|
|
196
|
-
totalTokens: 0,
|
|
197
|
-
cachedTokens: 0,
|
|
198
|
-
cacheWriteTokens: 0,
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const input = raw.inputTokens ?? 0
|
|
202
|
-
const output = raw.outputTokens ?? 0
|
|
203
|
-
return {
|
|
204
|
-
promptTokens: input,
|
|
205
|
-
completionTokens: output,
|
|
206
|
-
totalTokens: raw.totalTokens ?? input + output,
|
|
207
|
-
cachedTokens: raw.cacheReadInputTokenCount ?? 0,
|
|
208
|
-
cacheWriteTokens: raw.cacheWriteInputTokenCount ?? 0,
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
type NamzuFinishReason = ChatCompletionResponse['finishReason']
|
|
213
|
-
|
|
214
|
-
function mapStopReason(reason?: string): NamzuFinishReason {
|
|
215
|
-
switch (reason) {
|
|
216
|
-
case 'end_turn':
|
|
217
|
-
case 'stop_sequence':
|
|
218
|
-
return 'stop'
|
|
219
|
-
case 'tool_use':
|
|
220
|
-
return 'tool_calls'
|
|
221
|
-
case 'max_tokens':
|
|
222
|
-
return 'length'
|
|
223
|
-
case 'content_filtered':
|
|
224
|
-
return 'content_filter'
|
|
225
|
-
default:
|
|
226
|
-
return 'stop'
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function extractResponseContent(content?: ContentBlock[]): {
|
|
231
|
-
text: string | null
|
|
232
|
-
toolCalls: ChatCompletionResponse['message']['toolCalls']
|
|
233
|
-
} {
|
|
234
|
-
if (!content || content.length === 0) return { text: null, toolCalls: undefined }
|
|
235
|
-
|
|
236
|
-
let text: string | null = null
|
|
237
|
-
const toolCalls: NonNullable<ChatCompletionResponse['message']['toolCalls']> = []
|
|
238
|
-
|
|
239
|
-
for (const block of content) {
|
|
240
|
-
if ('text' in block && block.text) {
|
|
241
|
-
text = (text ?? '') + block.text
|
|
242
|
-
}
|
|
243
|
-
if ('toolUse' in block && block.toolUse) {
|
|
244
|
-
const tu = block.toolUse as ToolUseBlock
|
|
245
|
-
toolCalls.push({
|
|
246
|
-
id: tu.toolUseId ?? `tool-${Date.now()}`,
|
|
247
|
-
type: 'function',
|
|
248
|
-
function: {
|
|
249
|
-
name: tu.name ?? '',
|
|
250
|
-
arguments: JSON.stringify(tu.input ?? {}),
|
|
251
|
-
},
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
text,
|
|
258
|
-
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export class BedrockProvider implements LLMProvider {
|
|
263
|
-
readonly id = 'bedrock'
|
|
264
|
-
readonly name = 'AWS Bedrock'
|
|
265
|
-
|
|
266
|
-
private client: BedrockRuntimeClient
|
|
267
|
-
private config: BedrockConfig
|
|
268
|
-
|
|
269
|
-
constructor(config: BedrockConfig) {
|
|
270
|
-
this.config = config
|
|
271
|
-
|
|
272
|
-
const clientConfig: Record<string, unknown> = {}
|
|
273
|
-
|
|
274
|
-
if (config.region) {
|
|
275
|
-
clientConfig.region = config.region
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (config.accessKeyId && config.secretAccessKey) {
|
|
279
|
-
clientConfig.credentials = {
|
|
280
|
-
accessKeyId: config.accessKeyId,
|
|
281
|
-
secretAccessKey: config.secretAccessKey,
|
|
282
|
-
...(config.sessionToken ? { sessionToken: config.sessionToken } : {}),
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
this.client = new BedrockRuntimeClient(clientConfig)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async chat(params: ChatCompletionParams): Promise<ChatCompletionResponse> {
|
|
290
|
-
const tracer = getTracer()
|
|
291
|
-
|
|
292
|
-
return tracer.startActiveSpan(chatSpanName(params.model), async (span) => {
|
|
293
|
-
span.setAttributes({
|
|
294
|
-
[GENAI.OPERATION_NAME]: 'chat',
|
|
295
|
-
[GENAI.SYSTEM]: 'bedrock',
|
|
296
|
-
[GENAI.REQUEST_MODEL]: params.model,
|
|
297
|
-
})
|
|
298
|
-
if (params.temperature !== undefined) {
|
|
299
|
-
span.setAttribute(GENAI.REQUEST_TEMPERATURE, params.temperature)
|
|
300
|
-
}
|
|
301
|
-
if (params.maxTokens !== undefined) {
|
|
302
|
-
span.setAttribute(GENAI.REQUEST_MAX_TOKENS, params.maxTokens)
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
try {
|
|
306
|
-
const system = extractSystemBlocks(params.messages)
|
|
307
|
-
const messages = toBedrockMessages(params.messages)
|
|
308
|
-
const toolConfig = toBedrockToolConfig(params)
|
|
309
|
-
|
|
310
|
-
const inferenceConfig: Record<string, unknown> = {}
|
|
311
|
-
if (params.maxTokens !== undefined) inferenceConfig.maxTokens = params.maxTokens
|
|
312
|
-
if (params.temperature !== undefined) inferenceConfig.temperature = params.temperature
|
|
313
|
-
if (params.topP !== undefined) inferenceConfig.topP = params.topP
|
|
314
|
-
if (params.stop) inferenceConfig.stopSequences = params.stop
|
|
315
|
-
|
|
316
|
-
logger.debug('Sending Bedrock Converse request', {
|
|
317
|
-
model: params.model,
|
|
318
|
-
})
|
|
319
|
-
|
|
320
|
-
const command = new ConverseCommand({
|
|
321
|
-
modelId: params.model,
|
|
322
|
-
system: system.length > 0 ? system : undefined,
|
|
323
|
-
messages,
|
|
324
|
-
toolConfig,
|
|
325
|
-
inferenceConfig,
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
const response = await this.client.send(command, {
|
|
329
|
-
requestTimeout: this.config.timeout ?? 120_000,
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
const { text, toolCalls } = extractResponseContent(response.output?.message?.content)
|
|
333
|
-
const usage = parseUsage(response.usage as RawBedrockUsage | undefined)
|
|
334
|
-
const finishReason = mapStopReason(response.stopReason)
|
|
335
|
-
|
|
336
|
-
const requestId = response.$metadata.requestId ?? `bedrock-${Date.now()}`
|
|
337
|
-
|
|
338
|
-
const result: ChatCompletionResponse = {
|
|
339
|
-
id: requestId,
|
|
340
|
-
model: params.model,
|
|
341
|
-
message: {
|
|
342
|
-
role: 'assistant',
|
|
343
|
-
content: text,
|
|
344
|
-
toolCalls,
|
|
345
|
-
},
|
|
346
|
-
finishReason,
|
|
347
|
-
usage,
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
span.setAttributes({
|
|
351
|
-
[GENAI.RESPONSE_ID]: requestId,
|
|
352
|
-
[GENAI.RESPONSE_MODEL]: params.model,
|
|
353
|
-
[GENAI.RESPONSE_FINISH_REASONS]: finishReason,
|
|
354
|
-
[GENAI.USAGE_INPUT_TOKENS]: usage.promptTokens,
|
|
355
|
-
[GENAI.USAGE_OUTPUT_TOKENS]: usage.completionTokens,
|
|
356
|
-
[NAMZU.CACHE_READ_TOKENS]: usage.cachedTokens,
|
|
357
|
-
[NAMZU.CACHE_WRITE_TOKENS]: usage.cacheWriteTokens,
|
|
358
|
-
})
|
|
359
|
-
span.setStatus({ code: SpanStatusCode.OK })
|
|
360
|
-
|
|
361
|
-
return result
|
|
362
|
-
} catch (err) {
|
|
363
|
-
span.setStatus({
|
|
364
|
-
code: SpanStatusCode.ERROR,
|
|
365
|
-
message: toErrorMessage(err),
|
|
366
|
-
})
|
|
367
|
-
span.recordException(err instanceof Error ? err : new Error(String(err)))
|
|
368
|
-
throw err
|
|
369
|
-
} finally {
|
|
370
|
-
span.end()
|
|
371
|
-
}
|
|
372
|
-
})
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
async *chatStream(params: ChatCompletionParams): AsyncIterable<StreamChunk> {
|
|
376
|
-
const system = extractSystemBlocks(params.messages)
|
|
377
|
-
const messages = toBedrockMessages(params.messages)
|
|
378
|
-
const toolConfig = toBedrockToolConfig(params)
|
|
379
|
-
|
|
380
|
-
const inferenceConfig: Record<string, unknown> = {}
|
|
381
|
-
if (params.maxTokens !== undefined) inferenceConfig.maxTokens = params.maxTokens
|
|
382
|
-
if (params.temperature !== undefined) inferenceConfig.temperature = params.temperature
|
|
383
|
-
if (params.topP !== undefined) inferenceConfig.topP = params.topP
|
|
384
|
-
if (params.stop) inferenceConfig.stopSequences = params.stop
|
|
385
|
-
|
|
386
|
-
const command = new ConverseStreamCommand({
|
|
387
|
-
modelId: params.model,
|
|
388
|
-
system: system.length > 0 ? system : undefined,
|
|
389
|
-
messages,
|
|
390
|
-
toolConfig,
|
|
391
|
-
inferenceConfig,
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
const response = await this.client.send(command, {
|
|
395
|
-
requestTimeout: this.config.timeout ?? 120_000,
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
if (!response.stream) {
|
|
399
|
-
throw new Error('Bedrock returned no stream body')
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const requestId = response.$metadata.requestId ?? `bedrock-${Date.now()}`
|
|
403
|
-
|
|
404
|
-
const activeToolCalls = new Map<number, { id: string; name: string; args: string }>()
|
|
405
|
-
let toolCallIndex = 0
|
|
406
|
-
|
|
407
|
-
for await (const event of response.stream as AsyncIterable<ConverseStreamOutput>) {
|
|
408
|
-
try {
|
|
409
|
-
if ('contentBlockDelta' in event && event.contentBlockDelta?.delta) {
|
|
410
|
-
const delta = event.contentBlockDelta.delta
|
|
411
|
-
if ('text' in delta && delta.text) {
|
|
412
|
-
yield {
|
|
413
|
-
id: requestId,
|
|
414
|
-
delta: { content: delta.text },
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if ('toolUse' in delta && delta.toolUse) {
|
|
419
|
-
const idx = event.contentBlockDelta.contentBlockIndex ?? toolCallIndex
|
|
420
|
-
const active = activeToolCalls.get(idx)
|
|
421
|
-
if (active) {
|
|
422
|
-
active.args += delta.toolUse.input ?? ''
|
|
423
|
-
yield {
|
|
424
|
-
id: requestId,
|
|
425
|
-
delta: {
|
|
426
|
-
toolCalls: [
|
|
427
|
-
{
|
|
428
|
-
index: idx,
|
|
429
|
-
function: { arguments: delta.toolUse.input ?? '' },
|
|
430
|
-
},
|
|
431
|
-
],
|
|
432
|
-
},
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
if ('contentBlockStart' in event && event.contentBlockStart?.start) {
|
|
439
|
-
const start = event.contentBlockStart.start
|
|
440
|
-
if ('toolUse' in start && start.toolUse) {
|
|
441
|
-
const idx = event.contentBlockStart.contentBlockIndex ?? toolCallIndex
|
|
442
|
-
activeToolCalls.set(idx, {
|
|
443
|
-
id: start.toolUse.toolUseId ?? `tool-${Date.now()}`,
|
|
444
|
-
name: start.toolUse.name ?? '',
|
|
445
|
-
args: '',
|
|
446
|
-
})
|
|
447
|
-
yield {
|
|
448
|
-
id: requestId,
|
|
449
|
-
delta: {
|
|
450
|
-
toolCalls: [
|
|
451
|
-
{
|
|
452
|
-
index: idx,
|
|
453
|
-
id: start.toolUse.toolUseId,
|
|
454
|
-
type: 'function',
|
|
455
|
-
function: { name: start.toolUse.name ?? '' },
|
|
456
|
-
},
|
|
457
|
-
],
|
|
458
|
-
},
|
|
459
|
-
}
|
|
460
|
-
toolCallIndex = idx + 1
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if ('contentBlockStop' in event) {
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
if ('messageStop' in event && event.messageStop) {
|
|
468
|
-
yield {
|
|
469
|
-
id: requestId,
|
|
470
|
-
delta: {},
|
|
471
|
-
finishReason: mapStopReason(event.messageStop.stopReason),
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if ('metadata' in event && event.metadata?.usage) {
|
|
476
|
-
const usage = parseUsage(event.metadata.usage as RawBedrockUsage)
|
|
477
|
-
yield {
|
|
478
|
-
id: requestId,
|
|
479
|
-
delta: {},
|
|
480
|
-
usage,
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
} catch (parseErr) {
|
|
484
|
-
logger.warn('Failed to process Bedrock stream event', {
|
|
485
|
-
error: toErrorMessage(parseErr),
|
|
486
|
-
})
|
|
487
|
-
yield {
|
|
488
|
-
id: requestId,
|
|
489
|
-
delta: { content: undefined },
|
|
490
|
-
finishReason: undefined,
|
|
491
|
-
usage: undefined,
|
|
492
|
-
error: `Stream parse error: ${toErrorMessage(parseErr)}`,
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
async listModels(): Promise<ModelInfo[]> {
|
|
499
|
-
return [
|
|
500
|
-
{
|
|
501
|
-
id: 'anthropic.claude-sonnet-4-20250514',
|
|
502
|
-
name: 'Claude Sonnet 4 (Bedrock)',
|
|
503
|
-
contextWindow: 200_000,
|
|
504
|
-
maxOutputTokens: 64_000,
|
|
505
|
-
inputPrice: 3.0,
|
|
506
|
-
outputPrice: 15.0,
|
|
507
|
-
supportsToolUse: true,
|
|
508
|
-
supportsStreaming: true,
|
|
509
|
-
},
|
|
510
|
-
{
|
|
511
|
-
id: 'anthropic.claude-haiku-4-20250514',
|
|
512
|
-
name: 'Claude Haiku 4 (Bedrock)',
|
|
513
|
-
contextWindow: 200_000,
|
|
514
|
-
maxOutputTokens: 64_000,
|
|
515
|
-
inputPrice: 0.8,
|
|
516
|
-
outputPrice: 4.0,
|
|
517
|
-
supportsToolUse: true,
|
|
518
|
-
supportsStreaming: true,
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
id: 'amazon.nova-pro-v1:0',
|
|
522
|
-
name: 'Amazon Nova Pro',
|
|
523
|
-
contextWindow: 300_000,
|
|
524
|
-
maxOutputTokens: 5_000,
|
|
525
|
-
inputPrice: 0.8,
|
|
526
|
-
outputPrice: 3.2,
|
|
527
|
-
supportsToolUse: true,
|
|
528
|
-
supportsStreaming: true,
|
|
529
|
-
},
|
|
530
|
-
]
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
async healthCheck(): Promise<boolean> {
|
|
534
|
-
try {
|
|
535
|
-
const command = new ConverseCommand({
|
|
536
|
-
modelId: 'anthropic.claude-haiku-4-20250514',
|
|
537
|
-
messages: [{ role: 'user', content: [{ text: 'hi' }] }],
|
|
538
|
-
inferenceConfig: { maxTokens: 1 },
|
|
539
|
-
})
|
|
540
|
-
const response = await this.client.send(command, {
|
|
541
|
-
requestTimeout: 5000,
|
|
542
|
-
})
|
|
543
|
-
return response.$metadata.httpStatusCode === 200
|
|
544
|
-
} catch {
|
|
545
|
-
return false
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|