@boxiaolanya2008/pi-ai 0.60.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/README.md +1198 -0
- package/bedrock-provider.d.ts +1 -0
- package/bedrock-provider.js +1 -0
- package/dist/api-registry.d.ts +20 -0
- package/dist/api-registry.d.ts.map +1 -0
- package/dist/api-registry.js +44 -0
- package/dist/api-registry.js.map +1 -0
- package/dist/bedrock-provider.d.ts +5 -0
- package/dist/bedrock-provider.d.ts.map +1 -0
- package/dist/bedrock-provider.js +6 -0
- package/dist/bedrock-provider.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -0
- package/dist/env-api-keys.d.ts +4 -0
- package/dist/env-api-keys.d.ts.map +1 -0
- package/dist/env-api-keys.js +85 -0
- package/dist/env-api-keys.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +22 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.generated.d.ts +4 -0
- package/dist/models.generated.d.ts.map +1 -0
- package/dist/models.generated.js +11 -0
- package/dist/models.generated.js.map +1 -0
- package/dist/models.js +50 -0
- package/dist/models.js.map +1 -0
- package/dist/oauth.d.ts +2 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +2 -0
- package/dist/oauth.js.map +1 -0
- package/dist/providers/amazon-bedrock.d.ts +15 -0
- package/dist/providers/amazon-bedrock.d.ts.map +1 -0
- package/dist/providers/amazon-bedrock.js +552 -0
- package/dist/providers/amazon-bedrock.js.map +1 -0
- package/dist/providers/anthropic.d.ts +15 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +677 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/azure-openai-responses.d.ts +12 -0
- package/dist/providers/azure-openai-responses.d.ts.map +1 -0
- package/dist/providers/azure-openai-responses.js +181 -0
- package/dist/providers/azure-openai-responses.js.map +1 -0
- package/dist/providers/github-copilot-headers.d.ts +8 -0
- package/dist/providers/github-copilot-headers.d.ts.map +1 -0
- package/dist/providers/github-copilot-headers.js +26 -0
- package/dist/providers/github-copilot-headers.js.map +1 -0
- package/dist/providers/google-gemini-cli.d.ts +15 -0
- package/dist/providers/google-gemini-cli.d.ts.map +1 -0
- package/dist/providers/google-gemini-cli.js +43 -0
- package/dist/providers/google-gemini-cli.js.map +1 -0
- package/dist/providers/google-shared.d.ts +15 -0
- package/dist/providers/google-shared.d.ts.map +1 -0
- package/dist/providers/google-shared.js +226 -0
- package/dist/providers/google-shared.js.map +1 -0
- package/dist/providers/google-vertex.d.ts +15 -0
- package/dist/providers/google-vertex.d.ts.map +1 -0
- package/dist/providers/google-vertex.js +372 -0
- package/dist/providers/google-vertex.js.map +1 -0
- package/dist/providers/google.d.ts +13 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +351 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/mistral.d.ts +13 -0
- package/dist/providers/mistral.d.ts.map +1 -0
- package/dist/providers/mistral.js +489 -0
- package/dist/providers/mistral.js.map +1 -0
- package/dist/providers/openai-codex-responses.d.ts +9 -0
- package/dist/providers/openai-codex-responses.d.ts.map +1 -0
- package/dist/providers/openai-codex-responses.js +672 -0
- package/dist/providers/openai-codex-responses.js.map +1 -0
- package/dist/providers/openai-completions.d.ts +15 -0
- package/dist/providers/openai-completions.d.ts.map +1 -0
- package/dist/providers/openai-completions.js +651 -0
- package/dist/providers/openai-completions.js.map +1 -0
- package/dist/providers/openai-responses-shared.d.ts +17 -0
- package/dist/providers/openai-responses-shared.d.ts.map +1 -0
- package/dist/providers/openai-responses-shared.js +420 -0
- package/dist/providers/openai-responses-shared.js.map +1 -0
- package/dist/providers/openai-responses.d.ts +10 -0
- package/dist/providers/openai-responses.d.ts.map +1 -0
- package/dist/providers/openai-responses.js +186 -0
- package/dist/providers/openai-responses.js.map +1 -0
- package/dist/providers/register-builtins.d.ts +11 -0
- package/dist/providers/register-builtins.d.ts.map +1 -0
- package/dist/providers/register-builtins.js +138 -0
- package/dist/providers/register-builtins.js.map +1 -0
- package/dist/providers/simple-options.d.ts +8 -0
- package/dist/providers/simple-options.d.ts.map +1 -0
- package/dist/providers/simple-options.js +35 -0
- package/dist/providers/simple-options.js.map +1 -0
- package/dist/providers/transform-messages.d.ts +3 -0
- package/dist/providers/transform-messages.d.ts.map +1 -0
- package/dist/providers/transform-messages.js +130 -0
- package/dist/providers/transform-messages.js.map +1 -0
- package/dist/stream.d.ts +8 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +27 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +213 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/event-stream.d.ts +20 -0
- package/dist/utils/event-stream.d.ts.map +1 -0
- package/dist/utils/event-stream.js +77 -0
- package/dist/utils/event-stream.js.map +1 -0
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +13 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/json-parse.d.ts +2 -0
- package/dist/utils/json-parse.d.ts.map +1 -0
- package/dist/utils/json-parse.js +19 -0
- package/dist/utils/json-parse.js.map +1 -0
- package/dist/utils/oauth/anthropic.d.ts +4 -0
- package/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/dist/utils/oauth/anthropic.js +61 -0
- package/dist/utils/oauth/anthropic.js.map +1 -0
- package/dist/utils/oauth/github-copilot.d.ts +16 -0
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -0
- package/dist/utils/oauth/github-copilot.js +247 -0
- package/dist/utils/oauth/github-copilot.js.map +1 -0
- package/dist/utils/oauth/google-antigravity.d.ts +7 -0
- package/dist/utils/oauth/google-antigravity.d.ts.map +1 -0
- package/dist/utils/oauth/google-antigravity.js +55 -0
- package/dist/utils/oauth/google-antigravity.js.map +1 -0
- package/dist/utils/oauth/index.d.ts +18 -0
- package/dist/utils/oauth/index.d.ts.map +1 -0
- package/dist/utils/oauth/index.js +72 -0
- package/dist/utils/oauth/index.js.map +1 -0
- package/dist/utils/oauth/openai-codex.d.ts +14 -0
- package/dist/utils/oauth/openai-codex.d.ts.map +1 -0
- package/dist/utils/oauth/openai-codex.js +348 -0
- package/dist/utils/oauth/openai-codex.js.map +1 -0
- package/dist/utils/oauth/pkce.d.ts +5 -0
- package/dist/utils/oauth/pkce.d.ts.map +1 -0
- package/dist/utils/oauth/pkce.js +18 -0
- package/dist/utils/oauth/pkce.js.map +1 -0
- package/dist/utils/oauth/types.d.ts +40 -0
- package/dist/utils/oauth/types.d.ts.map +1 -0
- package/dist/utils/oauth/types.js +2 -0
- package/dist/utils/oauth/types.js.map +1 -0
- package/dist/utils/overflow.d.ts +4 -0
- package/dist/utils/overflow.d.ts.map +1 -0
- package/dist/utils/overflow.js +40 -0
- package/dist/utils/overflow.js.map +1 -0
- package/dist/utils/sanitize-unicode.d.ts +2 -0
- package/dist/utils/sanitize-unicode.d.ts.map +1 -0
- package/dist/utils/sanitize-unicode.js +4 -0
- package/dist/utils/sanitize-unicode.js.map +1 -0
- package/dist/utils/typebox-helpers.d.ts +6 -0
- package/dist/utils/typebox-helpers.d.ts.map +1 -0
- package/dist/utils/typebox-helpers.js +10 -0
- package/dist/utils/typebox-helpers.js.map +1 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +45 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amazon-bedrock.d.ts","sourceRoot":"","sources":["../../src/providers/amazon-bedrock.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAMX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAEb,eAAe,EAEf,aAAa,EAIb,MAAM,aAAa,CAAC;AAMrB,MAAM,WAAW,cAAe,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,yBAAyB,EAAE,cAAc,CAgInF,CAAC;AACF,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,yBAAyB,EAAE,mBAAmB,CAsC9F,CAAC","sourcesContent":["import {\n\tBedrockRuntimeClient,\n\ttype BedrockRuntimeClientConfig,\n\tStopReason as BedrockStopReason,\n\ttype Tool as BedrockTool,\n\tCachePointType,\n\tCacheTTL,\n\ttype ContentBlock,\n\ttype ContentBlockDeltaEvent,\n\ttype ContentBlockStartEvent,\n\ttype ContentBlockStopEvent,\n\tConversationRole,\n\tConverseStreamCommand,\n\ttype ConverseStreamMetadataEvent,\n\tImageFormat,\n\ttype Message,\n\ttype SystemContentBlock,\n\ttype ToolChoice,\n\ttype ToolConfiguration,\n\tToolResultStatus,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport { calculateCost } from \"../models.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingBudgets,\n\tThinkingContent,\n\tThinkingLevel,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { parseStreamingJson } from \"../utils/json-parse.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { adjustMaxTokensForThinking, buildBaseOptions, clampReasoning } from \"./simple-options.js\";\nimport { transformMessages } from \"./transform-messages.js\";\nexport interface BedrockOptions extends StreamOptions {\n\tregion?: string;\n\tprofile?: string;\n\ttoolChoice?: \"auto\" | \"any\" | \"none\" | { type: \"tool\"; name: string };\n\treasoning?: ThinkingLevel;\n\tthinkingBudgets?: ThinkingBudgets;\n\tinterleavedThinking?: boolean;\n}\ntype Block = (TextContent | ThinkingContent | ToolCall) & { index?: number; partialJson?: string };\nexport const streamBedrock: StreamFunction<\"bedrock-converse-stream\", BedrockOptions> = (\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions: BedrockOptions = {},\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"bedrock-converse-stream\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tconst blocks = output.content as Block[];\n\t\tconst config: BedrockRuntimeClientConfig = {\n\t\t\tprofile: options.profile,\n\t\t};\n\t\tif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\t\t\tconst explicitRegion = options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;\n\t\t\tif (explicitRegion) {\n\t\t\t\tconfig.region = explicitRegion;\n\t\t\t} else if (!process.env.AWS_PROFILE) {\n\t\t\t\tconfig.region = \"us-east-1\";\n\t\t\t}\n\t\t\tif (process.env.AWS_BEDROCK_SKIP_AUTH === \"1\") {\n\t\t\t\tconfig.credentials = {\n\t\t\t\t\taccessKeyId: \"dummy-access-key\",\n\t\t\t\t\tsecretAccessKey: \"dummy-secret-key\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (\n\t\t\t\tprocess.env.HTTP_PROXY ||\n\t\t\t\tprocess.env.HTTPS_PROXY ||\n\t\t\t\tprocess.env.NO_PROXY ||\n\t\t\t\tprocess.env.http_proxy ||\n\t\t\t\tprocess.env.https_proxy ||\n\t\t\t\tprocess.env.no_proxy\n\t\t\t) {\n\t\t\t\tconst nodeHttpHandler = await import(\"@smithy/node-http-handler\");\n\t\t\t\tconst proxyAgent = await import(\"proxy-agent\");\n\t\t\t\tconst agent = new proxyAgent.ProxyAgent();\n\t\t\t\tconfig.requestHandler = new nodeHttpHandler.NodeHttpHandler({\n\t\t\t\t\thttpAgent: agent,\n\t\t\t\t\thttpsAgent: agent,\n\t\t\t\t});\n\t\t\t} else if (process.env.AWS_BEDROCK_FORCE_HTTP1 === \"1\") {\n\t\t\t\tconst nodeHttpHandler = await import(\"@smithy/node-http-handler\");\n\t\t\t\tconfig.requestHandler = new nodeHttpHandler.NodeHttpHandler();\n\t\t\t}\n\t\t} else {\n\t\t\tconfig.region = options.region || \"us-east-1\";\n\t\t}\n\t\ttry {\n\t\t\tconst client = new BedrockRuntimeClient(config);\n\t\t\tconst cacheRetention = resolveCacheRetention(options.cacheRetention);\n\t\t\tlet commandInput = {\n\t\t\t\tmodelId: model.id,\n\t\t\t\tmessages: convertMessages(context, model, cacheRetention),\n\t\t\t\tsystem: buildSystemPrompt(context.systemPrompt, model, cacheRetention),\n\t\t\t\tinferenceConfig: { maxTokens: options.maxTokens, temperature: options.temperature },\n\t\t\t\ttoolConfig: convertToolConfig(context.tools, options.toolChoice),\n\t\t\t\tadditionalModelRequestFields: buildAdditionalModelRequestFields(model, options),\n\t\t\t};\n\t\t\tconst nextCommandInput = await options?.onPayload?.(commandInput, model);\n\t\t\tif (nextCommandInput !== undefined) {\n\t\t\t\tcommandInput = nextCommandInput as typeof commandInput;\n\t\t\t}\n\t\t\tconst command = new ConverseStreamCommand(commandInput);\n\t\t\tconst response = await client.send(command, { abortSignal: options.signal });\n\t\t\tfor await (const item of response.stream!) {\n\t\t\t\tif (item.messageStart) {\n\t\t\t\t\tif (item.messageStart.role !== ConversationRole.ASSISTANT) {\n\t\t\t\t\t\tthrow new Error(\"Unexpected assistant message start but got user message start instead\");\n\t\t\t\t\t}\n\t\t\t\t\tstream.push({ type: \"start\", partial: output });\n\t\t\t\t} else if (item.contentBlockStart) {\n\t\t\t\t\thandleContentBlockStart(item.contentBlockStart, blocks, output, stream);\n\t\t\t\t} else if (item.contentBlockDelta) {\n\t\t\t\t\thandleContentBlockDelta(item.contentBlockDelta, blocks, output, stream);\n\t\t\t\t} else if (item.contentBlockStop) {\n\t\t\t\t\thandleContentBlockStop(item.contentBlockStop, blocks, output, stream);\n\t\t\t\t} else if (item.messageStop) {\n\t\t\t\t\toutput.stopReason = mapStopReason(item.messageStop.stopReason);\n\t\t\t\t} else if (item.metadata) {\n\t\t\t\t\thandleMetadata(item.metadata, model, output);\n\t\t\t\t} else if (item.internalServerException) {\n\t\t\t\t\tthrow new Error(`Internal server error: ${item.internalServerException.message}`);\n\t\t\t\t} else if (item.modelStreamErrorException) {\n\t\t\t\t\tthrow new Error(`Model stream error: ${item.modelStreamErrorException.message}`);\n\t\t\t\t} else if (item.validationException) {\n\t\t\t\t\tthrow new Error(`Validation error: ${item.validationException.message}`);\n\t\t\t\t} else if (item.throttlingException) {\n\t\t\t\t\tthrow new Error(`Throttling error: ${item.throttlingException.message}`);\n\t\t\t\t} else if (item.serviceUnavailableException) {\n\t\t\t\t\tthrow new Error(`Service unavailable: ${item.serviceUnavailableException.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"error\" || output.stopReason === \"aborted\") {\n\t\t\t\tthrow new Error(\"An unknown error occurred\");\n\t\t\t}\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as Block).index;\n\t\t\t\tdelete (block as Block).partialJson;\n\t\t\t}\n\t\t\toutput.stopReason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\treturn stream;\n};\nexport const streamSimpleBedrock: StreamFunction<\"bedrock-converse-stream\", SimpleStreamOptions> = (\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst base = buildBaseOptions(model, options, undefined);\n\tif (!options?.reasoning) {\n\t\treturn streamBedrock(model, context, { ...base, reasoning: undefined } satisfies BedrockOptions);\n\t}\n\tif (model.id.includes(\"anthropic.claude\") || model.id.includes(\"anthropic/claude\")) {\n\t\tif (supportsAdaptiveThinking(model.id)) {\n\t\t\treturn streamBedrock(model, context, {\n\t\t\t\t...base,\n\t\t\t\treasoning: options.reasoning,\n\t\t\t\tthinkingBudgets: options.thinkingBudgets,\n\t\t\t} satisfies BedrockOptions);\n\t\t}\n\t\tconst adjusted = adjustMaxTokensForThinking(\n\t\t\tbase.maxTokens || 0,\n\t\t\tmodel.maxTokens,\n\t\t\toptions.reasoning,\n\t\t\toptions.thinkingBudgets,\n\t\t);\n\t\treturn streamBedrock(model, context, {\n\t\t\t...base,\n\t\t\tmaxTokens: adjusted.maxTokens,\n\t\t\treasoning: options.reasoning,\n\t\t\tthinkingBudgets: {\n\t\t\t\t...(options.thinkingBudgets || {}),\n\t\t\t\t[clampReasoning(options.reasoning)!]: adjusted.thinkingBudget,\n\t\t\t},\n\t\t} satisfies BedrockOptions);\n\t}\n\treturn streamBedrock(model, context, {\n\t\t...base,\n\t\treasoning: options.reasoning,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t} satisfies BedrockOptions);\n};\nfunction handleContentBlockStart(\n\tevent: ContentBlockStartEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst index = event.contentBlockIndex!;\n\tconst start = event.start;\n\tif (start?.toolUse) {\n\t\tconst block: Block = {\n\t\t\ttype: \"toolCall\",\n\t\t\tid: start.toolUse.toolUseId || \"\",\n\t\t\tname: start.toolUse.name || \"\",\n\t\t\targuments: {},\n\t\t\tpartialJson: \"\",\n\t\t\tindex,\n\t\t};\n\t\toutput.content.push(block);\n\t\tstream.push({ type: \"toolcall_start\", contentIndex: blocks.length - 1, partial: output });\n\t}\n}\nfunction handleContentBlockDelta(\n\tevent: ContentBlockDeltaEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst contentBlockIndex = event.contentBlockIndex!;\n\tconst delta = event.delta;\n\tlet index = blocks.findIndex((b) => b.index === contentBlockIndex);\n\tlet block = blocks[index];\n\tif (delta?.text !== undefined) {\n\t\tif (!block) {\n\t\t\tconst newBlock: Block = { type: \"text\", text: \"\", index: contentBlockIndex };\n\t\t\toutput.content.push(newBlock);\n\t\t\tindex = blocks.length - 1;\n\t\t\tblock = blocks[index];\n\t\t\tstream.push({ type: \"text_start\", contentIndex: index, partial: output });\n\t\t}\n\t\tif (block.type === \"text\") {\n\t\t\tblock.text += delta.text;\n\t\t\tstream.push({ type: \"text_delta\", contentIndex: index, delta: delta.text, partial: output });\n\t\t}\n\t} else if (delta?.toolUse && block?.type === \"toolCall\") {\n\t\tblock.partialJson = (block.partialJson || \"\") + (delta.toolUse.input || \"\");\n\t\tblock.arguments = parseStreamingJson(block.partialJson);\n\t\tstream.push({ type: \"toolcall_delta\", contentIndex: index, delta: delta.toolUse.input || \"\", partial: output });\n\t} else if (delta?.reasoningContent) {\n\t\tlet thinkingBlock = block;\n\t\tlet thinkingIndex = index;\n\t\tif (!thinkingBlock) {\n\t\t\tconst newBlock: Block = { type: \"thinking\", thinking: \"\", thinkingSignature: \"\", index: contentBlockIndex };\n\t\t\toutput.content.push(newBlock);\n\t\t\tthinkingIndex = blocks.length - 1;\n\t\t\tthinkingBlock = blocks[thinkingIndex];\n\t\t\tstream.push({ type: \"thinking_start\", contentIndex: thinkingIndex, partial: output });\n\t\t}\n\t\tif (thinkingBlock?.type === \"thinking\") {\n\t\t\tif (delta.reasoningContent.text) {\n\t\t\t\tthinkingBlock.thinking += delta.reasoningContent.text;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: thinkingIndex,\n\t\t\t\t\tdelta: delta.reasoningContent.text,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (delta.reasoningContent.signature) {\n\t\t\t\tthinkingBlock.thinkingSignature =\n\t\t\t\t\t(thinkingBlock.thinkingSignature || \"\") + delta.reasoningContent.signature;\n\t\t\t}\n\t\t}\n\t}\n}\nfunction handleMetadata(\n\tevent: ConverseStreamMetadataEvent,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toutput: AssistantMessage,\n): void {\n\tif (event.usage) {\n\t\toutput.usage.input = event.usage.inputTokens || 0;\n\t\toutput.usage.output = event.usage.outputTokens || 0;\n\t\toutput.usage.cacheRead = event.usage.cacheReadInputTokens || 0;\n\t\toutput.usage.cacheWrite = event.usage.cacheWriteInputTokens || 0;\n\t\toutput.usage.totalTokens = event.usage.totalTokens || output.usage.input + output.usage.output;\n\t\tcalculateCost(model, output.usage);\n\t}\n}\nfunction handleContentBlockStop(\n\tevent: ContentBlockStopEvent,\n\tblocks: Block[],\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n): void {\n\tconst index = blocks.findIndex((b) => b.index === event.contentBlockIndex);\n\tconst block = blocks[index];\n\tif (!block) return;\n\tdelete (block as Block).index;\n\tswitch (block.type) {\n\t\tcase \"text\":\n\t\t\tstream.push({ type: \"text_end\", contentIndex: index, content: block.text, partial: output });\n\t\t\tbreak;\n\t\tcase \"thinking\":\n\t\t\tstream.push({ type: \"thinking_end\", contentIndex: index, content: block.thinking, partial: output });\n\t\t\tbreak;\n\t\tcase \"toolCall\":\n\t\t\tblock.arguments = parseStreamingJson(block.partialJson);\n\t\t\tdelete (block as Block).partialJson;\n\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: index, toolCall: block, partial: output });\n\t\t\tbreak;\n\t}\n}\nfunction supportsAdaptiveThinking(modelId: string): boolean {\n\treturn (\n\t\tmodelId.includes(\"opus-4-6\") ||\n\t\tmodelId.includes(\"opus-4.6\") ||\n\t\tmodelId.includes(\"sonnet-4-6\") ||\n\t\tmodelId.includes(\"sonnet-4.6\")\n\t);\n}\nfunction mapThinkingLevelToEffort(\n\tlevel: SimpleStreamOptions[\"reasoning\"],\n\tmodelId: string,\n): \"low\" | \"medium\" | \"high\" | \"max\" {\n\tswitch (level) {\n\t\tcase \"minimal\":\n\t\tcase \"low\":\n\t\t\treturn \"low\";\n\t\tcase \"medium\":\n\t\t\treturn \"medium\";\n\t\tcase \"high\":\n\t\t\treturn \"high\";\n\t\tcase \"xhigh\":\n\t\t\treturn modelId.includes(\"opus-4-6\") || modelId.includes(\"opus-4.6\") ? \"max\" : \"high\";\n\t\tdefault:\n\t\t\treturn \"high\";\n\t}\n}\nfunction resolveCacheRetention(cacheRetention?: CacheRetention): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (typeof process !== \"undefined\" && process.env.PI_CACHE_RETENTION === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\nfunction supportsPromptCaching(model: Model<\"bedrock-converse-stream\">): boolean {\n\tif (model.cost.cacheRead || model.cost.cacheWrite) {\n\t\treturn true;\n\t}\n\tconst id = model.id.toLowerCase();\n\tif (id.includes(\"claude\") && (id.includes(\"-4-\") || id.includes(\"-4.\"))) return true;\n\tif (id.includes(\"claude-3-7-sonnet\")) return true;\n\tif (id.includes(\"claude-3-5-haiku\")) return true;\n\treturn false;\n}\nfunction supportsThinkingSignature(model: Model<\"bedrock-converse-stream\">): boolean {\n\tconst id = model.id.toLowerCase();\n\treturn id.includes(\"anthropic.claude\") || id.includes(\"anthropic/claude\");\n}\nfunction buildSystemPrompt(\n\tsystemPrompt: string | undefined,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): SystemContentBlock[] | undefined {\n\tif (!systemPrompt) return undefined;\n\tconst blocks: SystemContentBlock[] = [{ text: sanitizeSurrogates(systemPrompt) }];\n\tif (cacheRetention !== \"none\" && supportsPromptCaching(model)) {\n\t\tblocks.push({\n\t\t\tcachePoint: { type: CachePointType.DEFAULT, ...(cacheRetention === \"long\" ? { ttl: CacheTTL.ONE_HOUR } : {}) },\n\t\t});\n\t}\n\treturn blocks;\n}\nfunction normalizeToolCallId(id: string): string {\n\tconst sanitized = id.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\treturn sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n}\nfunction convertMessages(\n\tcontext: Context,\n\tmodel: Model<\"bedrock-converse-stream\">,\n\tcacheRetention: CacheRetention,\n): Message[] {\n\tconst result: Message[] = [];\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\tfor (let i = 0; i < transformedMessages.length; i++) {\n\t\tconst m = transformedMessages[i];\n\t\tswitch (m.role) {\n\t\t\tcase \"user\":\n\t\t\t\tresult.push({\n\t\t\t\t\trole: ConversationRole.USER,\n\t\t\t\t\tcontent:\n\t\t\t\t\t\ttypeof m.content === \"string\"\n\t\t\t\t\t\t\t? [{ text: sanitizeSurrogates(m.content) }]\n\t\t\t\t\t\t\t: m.content.map((c) => {\n\t\t\t\t\t\t\t\t\tswitch (c.type) {\n\t\t\t\t\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t\t\t\t\treturn { text: sanitizeSurrogates(c.text) };\n\t\t\t\t\t\t\t\t\t\tcase \"image\":\n\t\t\t\t\t\t\t\t\t\t\treturn { image: createImageBlock(c.mimeType, c.data) };\n\t\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Unknown user content type\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"assistant\": {\n\t\t\t\tif (m.content.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst contentBlocks: ContentBlock[] = [];\n\t\t\t\tfor (const c of m.content) {\n\t\t\t\t\tswitch (c.type) {\n\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\tif (c.text.trim().length === 0) continue;\n\t\t\t\t\t\t\tcontentBlocks.push({ text: sanitizeSurrogates(c.text) });\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"toolCall\":\n\t\t\t\t\t\t\tcontentBlocks.push({\n\t\t\t\t\t\t\t\ttoolUse: { toolUseId: c.id, name: c.name, input: c.arguments },\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"thinking\":\n\t\t\t\t\t\t\tif (c.thinking.trim().length === 0) continue;\n\t\t\t\t\t\t\tif (supportsThinkingSignature(model)) {\n\t\t\t\t\t\t\t\tcontentBlocks.push({\n\t\t\t\t\t\t\t\t\treasoningContent: {\n\t\t\t\t\t\t\t\t\t\treasoningText: { text: sanitizeSurrogates(c.thinking), signature: c.thinkingSignature },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcontentBlocks.push({\n\t\t\t\t\t\t\t\t\treasoningContent: {\n\t\t\t\t\t\t\t\t\t\treasoningText: { text: sanitizeSurrogates(c.thinking) },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new Error(\"Unknown assistant content type\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (contentBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tresult.push({\n\t\t\t\t\trole: ConversationRole.ASSISTANT,\n\t\t\t\t\tcontent: contentBlocks,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolResult\": {\n\t\t\t\tconst toolResults: ContentBlock.ToolResultMember[] = [];\n\t\t\t\ttoolResults.push({\n\t\t\t\t\ttoolResult: {\n\t\t\t\t\t\ttoolUseId: m.toolCallId,\n\t\t\t\t\t\tcontent: m.content.map((c) =>\n\t\t\t\t\t\t\tc.type === \"image\"\n\t\t\t\t\t\t\t\t? { image: createImageBlock(c.mimeType, c.data) }\n\t\t\t\t\t\t\t\t: { text: sanitizeSurrogates(c.text) },\n\t\t\t\t\t\t),\n\t\t\t\t\t\tstatus: m.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tlet j = i + 1;\n\t\t\t\twhile (j < transformedMessages.length && transformedMessages[j].role === \"toolResult\") {\n\t\t\t\t\tconst nextMsg = transformedMessages[j] as ToolResultMessage;\n\t\t\t\t\ttoolResults.push({\n\t\t\t\t\t\ttoolResult: {\n\t\t\t\t\t\t\ttoolUseId: nextMsg.toolCallId,\n\t\t\t\t\t\t\tcontent: nextMsg.content.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\"\n\t\t\t\t\t\t\t\t\t? { image: createImageBlock(c.mimeType, c.data) }\n\t\t\t\t\t\t\t\t\t: { text: sanitizeSurrogates(c.text) },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tstatus: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\ti = j - 1;\n\t\t\t\tresult.push({\n\t\t\t\t\trole: ConversationRole.USER,\n\t\t\t\t\tcontent: toolResults,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\"Unknown message role\");\n\t\t}\n\t}\n\tif (cacheRetention !== \"none\" && supportsPromptCaching(model) && result.length > 0) {\n\t\tconst lastMessage = result[result.length - 1];\n\t\tif (lastMessage.role === ConversationRole.USER && lastMessage.content) {\n\t\t\t(lastMessage.content as ContentBlock[]).push({\n\t\t\t\tcachePoint: {\n\t\t\t\t\ttype: CachePointType.DEFAULT,\n\t\t\t\t\t...(cacheRetention === \"long\" ? { ttl: CacheTTL.ONE_HOUR } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\nfunction convertToolConfig(\n\ttools: Tool[] | undefined,\n\ttoolChoice: BedrockOptions[\"toolChoice\"],\n): ToolConfiguration | undefined {\n\tif (!tools?.length || toolChoice === \"none\") return undefined;\n\tconst bedrockTools: BedrockTool[] = tools.map((tool) => ({\n\t\ttoolSpec: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tinputSchema: { json: tool.parameters },\n\t\t},\n\t}));\n\tlet bedrockToolChoice: ToolChoice | undefined;\n\tswitch (toolChoice) {\n\t\tcase \"auto\":\n\t\t\tbedrockToolChoice = { auto: {} };\n\t\t\tbreak;\n\t\tcase \"any\":\n\t\t\tbedrockToolChoice = { any: {} };\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (toolChoice?.type === \"tool\") {\n\t\t\t\tbedrockToolChoice = { tool: { name: toolChoice.name } };\n\t\t\t}\n\t}\n\treturn { tools: bedrockTools, toolChoice: bedrockToolChoice };\n}\nfunction mapStopReason(reason: string | undefined): StopReason {\n\tswitch (reason) {\n\t\tcase BedrockStopReason.END_TURN:\n\t\tcase BedrockStopReason.STOP_SEQUENCE:\n\t\t\treturn \"stop\";\n\t\tcase BedrockStopReason.MAX_TOKENS:\n\t\tcase BedrockStopReason.MODEL_CONTEXT_WINDOW_EXCEEDED:\n\t\t\treturn \"length\";\n\t\tcase BedrockStopReason.TOOL_USE:\n\t\t\treturn \"toolUse\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\nfunction buildAdditionalModelRequestFields(\n\tmodel: Model<\"bedrock-converse-stream\">,\n\toptions: BedrockOptions,\n): Record<string, any> | undefined {\n\tif (!options.reasoning || !model.reasoning) {\n\t\treturn undefined;\n\t}\n\tif (model.id.includes(\"anthropic.claude\") || model.id.includes(\"anthropic/claude\")) {\n\t\tconst result: Record<string, any> = supportsAdaptiveThinking(model.id)\n\t\t\t? {\n\t\t\t\t\tthinking: { type: \"adaptive\" },\n\t\t\t\t\toutput_config: { effort: mapThinkingLevelToEffort(options.reasoning, model.id) },\n\t\t\t\t}\n\t\t\t: (() => {\n\t\t\t\t\tconst defaultBudgets: Record<ThinkingLevel, number> = {\n\t\t\t\t\t\tminimal: 1024,\n\t\t\t\t\t\tlow: 2048,\n\t\t\t\t\t\tmedium: 8192,\n\t\t\t\t\t\thigh: 16384,\n\t\t\t\t\t\txhigh: 16384,\n\t\t\t\t\t};\n\t\t\t\t\tconst level = options.reasoning === \"xhigh\" ? \"high\" : options.reasoning;\n\t\t\t\t\tconst budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning];\n\t\t\t\t\treturn {\n\t\t\t\t\t\tthinking: {\n\t\t\t\t\t\t\ttype: \"enabled\",\n\t\t\t\t\t\t\tbudget_tokens: budget,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t})();\n\t\tif (!supportsAdaptiveThinking(model.id) && (options.interleavedThinking ?? true)) {\n\t\t\tresult.anthropic_beta = [\"interleaved-thinking-2025-05-14\"];\n\t\t}\n\t\treturn result;\n\t}\n\treturn undefined;\n}\nfunction createImageBlock(mimeType: string, data: string) {\n\tlet format: ImageFormat;\n\tswitch (mimeType) {\n\t\tcase \"image/jpeg\":\n\t\tcase \"image/jpg\":\n\t\t\tformat = ImageFormat.JPEG;\n\t\t\tbreak;\n\t\tcase \"image/png\":\n\t\t\tformat = ImageFormat.PNG;\n\t\t\tbreak;\n\t\tcase \"image/gif\":\n\t\t\tformat = ImageFormat.GIF;\n\t\t\tbreak;\n\t\tcase \"image/webp\":\n\t\t\tformat = ImageFormat.WEBP;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown image type: ${mimeType}`);\n\t}\n\tconst binaryString = atob(data);\n\tconst bytes = new Uint8Array(binaryString.length);\n\tfor (let i = 0; i < binaryString.length; i++) {\n\t\tbytes[i] = binaryString.charCodeAt(i);\n\t}\n\treturn { source: { bytes }, format };\n}\n"]}
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import { BedrockRuntimeClient, StopReason as BedrockStopReason, CachePointType, CacheTTL, ConversationRole, ConverseStreamCommand, ImageFormat, ToolResultStatus, } from "@aws-sdk/client-bedrock-runtime";
|
|
2
|
+
import { calculateCost } from "../models.js";
|
|
3
|
+
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
4
|
+
import { parseStreamingJson } from "../utils/json-parse.js";
|
|
5
|
+
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
6
|
+
import { adjustMaxTokensForThinking, buildBaseOptions, clampReasoning } from "./simple-options.js";
|
|
7
|
+
import { transformMessages } from "./transform-messages.js";
|
|
8
|
+
export const streamBedrock = (model, context, options = {}) => {
|
|
9
|
+
const stream = new AssistantMessageEventStream();
|
|
10
|
+
(async () => {
|
|
11
|
+
const output = {
|
|
12
|
+
role: "assistant",
|
|
13
|
+
content: [],
|
|
14
|
+
api: "bedrock-converse-stream",
|
|
15
|
+
provider: model.provider,
|
|
16
|
+
model: model.id,
|
|
17
|
+
usage: {
|
|
18
|
+
input: 0,
|
|
19
|
+
output: 0,
|
|
20
|
+
cacheRead: 0,
|
|
21
|
+
cacheWrite: 0,
|
|
22
|
+
totalTokens: 0,
|
|
23
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
24
|
+
},
|
|
25
|
+
stopReason: "stop",
|
|
26
|
+
timestamp: Date.now(),
|
|
27
|
+
};
|
|
28
|
+
const blocks = output.content;
|
|
29
|
+
const config = {
|
|
30
|
+
profile: options.profile,
|
|
31
|
+
};
|
|
32
|
+
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
33
|
+
const explicitRegion = options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
|
|
34
|
+
if (explicitRegion) {
|
|
35
|
+
config.region = explicitRegion;
|
|
36
|
+
}
|
|
37
|
+
else if (!process.env.AWS_PROFILE) {
|
|
38
|
+
config.region = "us-east-1";
|
|
39
|
+
}
|
|
40
|
+
if (process.env.AWS_BEDROCK_SKIP_AUTH === "1") {
|
|
41
|
+
config.credentials = {
|
|
42
|
+
accessKeyId: "dummy-access-key",
|
|
43
|
+
secretAccessKey: "dummy-secret-key",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (process.env.HTTP_PROXY ||
|
|
47
|
+
process.env.HTTPS_PROXY ||
|
|
48
|
+
process.env.NO_PROXY ||
|
|
49
|
+
process.env.http_proxy ||
|
|
50
|
+
process.env.https_proxy ||
|
|
51
|
+
process.env.no_proxy) {
|
|
52
|
+
const nodeHttpHandler = await import("@smithy/node-http-handler");
|
|
53
|
+
const proxyAgent = await import("proxy-agent");
|
|
54
|
+
const agent = new proxyAgent.ProxyAgent();
|
|
55
|
+
config.requestHandler = new nodeHttpHandler.NodeHttpHandler({
|
|
56
|
+
httpAgent: agent,
|
|
57
|
+
httpsAgent: agent,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
else if (process.env.AWS_BEDROCK_FORCE_HTTP1 === "1") {
|
|
61
|
+
const nodeHttpHandler = await import("@smithy/node-http-handler");
|
|
62
|
+
config.requestHandler = new nodeHttpHandler.NodeHttpHandler();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
config.region = options.region || "us-east-1";
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const client = new BedrockRuntimeClient(config);
|
|
70
|
+
const cacheRetention = resolveCacheRetention(options.cacheRetention);
|
|
71
|
+
let commandInput = {
|
|
72
|
+
modelId: model.id,
|
|
73
|
+
messages: convertMessages(context, model, cacheRetention),
|
|
74
|
+
system: buildSystemPrompt(context.systemPrompt, model, cacheRetention),
|
|
75
|
+
inferenceConfig: { maxTokens: options.maxTokens, temperature: options.temperature },
|
|
76
|
+
toolConfig: convertToolConfig(context.tools, options.toolChoice),
|
|
77
|
+
additionalModelRequestFields: buildAdditionalModelRequestFields(model, options),
|
|
78
|
+
};
|
|
79
|
+
const nextCommandInput = await options?.onPayload?.(commandInput, model);
|
|
80
|
+
if (nextCommandInput !== undefined) {
|
|
81
|
+
commandInput = nextCommandInput;
|
|
82
|
+
}
|
|
83
|
+
const command = new ConverseStreamCommand(commandInput);
|
|
84
|
+
const response = await client.send(command, { abortSignal: options.signal });
|
|
85
|
+
for await (const item of response.stream) {
|
|
86
|
+
if (item.messageStart) {
|
|
87
|
+
if (item.messageStart.role !== ConversationRole.ASSISTANT) {
|
|
88
|
+
throw new Error("Unexpected assistant message start but got user message start instead");
|
|
89
|
+
}
|
|
90
|
+
stream.push({ type: "start", partial: output });
|
|
91
|
+
}
|
|
92
|
+
else if (item.contentBlockStart) {
|
|
93
|
+
handleContentBlockStart(item.contentBlockStart, blocks, output, stream);
|
|
94
|
+
}
|
|
95
|
+
else if (item.contentBlockDelta) {
|
|
96
|
+
handleContentBlockDelta(item.contentBlockDelta, blocks, output, stream);
|
|
97
|
+
}
|
|
98
|
+
else if (item.contentBlockStop) {
|
|
99
|
+
handleContentBlockStop(item.contentBlockStop, blocks, output, stream);
|
|
100
|
+
}
|
|
101
|
+
else if (item.messageStop) {
|
|
102
|
+
output.stopReason = mapStopReason(item.messageStop.stopReason);
|
|
103
|
+
}
|
|
104
|
+
else if (item.metadata) {
|
|
105
|
+
handleMetadata(item.metadata, model, output);
|
|
106
|
+
}
|
|
107
|
+
else if (item.internalServerException) {
|
|
108
|
+
throw new Error(`Internal server error: ${item.internalServerException.message}`);
|
|
109
|
+
}
|
|
110
|
+
else if (item.modelStreamErrorException) {
|
|
111
|
+
throw new Error(`Model stream error: ${item.modelStreamErrorException.message}`);
|
|
112
|
+
}
|
|
113
|
+
else if (item.validationException) {
|
|
114
|
+
throw new Error(`Validation error: ${item.validationException.message}`);
|
|
115
|
+
}
|
|
116
|
+
else if (item.throttlingException) {
|
|
117
|
+
throw new Error(`Throttling error: ${item.throttlingException.message}`);
|
|
118
|
+
}
|
|
119
|
+
else if (item.serviceUnavailableException) {
|
|
120
|
+
throw new Error(`Service unavailable: ${item.serviceUnavailableException.message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (options.signal?.aborted) {
|
|
124
|
+
throw new Error("Request was aborted");
|
|
125
|
+
}
|
|
126
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
127
|
+
throw new Error("An unknown error occurred");
|
|
128
|
+
}
|
|
129
|
+
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
130
|
+
stream.end();
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
for (const block of output.content) {
|
|
134
|
+
delete block.index;
|
|
135
|
+
delete block.partialJson;
|
|
136
|
+
}
|
|
137
|
+
output.stopReason = options.signal?.aborted ? "aborted" : "error";
|
|
138
|
+
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
139
|
+
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
140
|
+
stream.end();
|
|
141
|
+
}
|
|
142
|
+
})();
|
|
143
|
+
return stream;
|
|
144
|
+
};
|
|
145
|
+
export const streamSimpleBedrock = (model, context, options) => {
|
|
146
|
+
const base = buildBaseOptions(model, options, undefined);
|
|
147
|
+
if (!options?.reasoning) {
|
|
148
|
+
return streamBedrock(model, context, { ...base, reasoning: undefined });
|
|
149
|
+
}
|
|
150
|
+
if (model.id.includes("anthropic.claude") || model.id.includes("anthropic/claude")) {
|
|
151
|
+
if (supportsAdaptiveThinking(model.id)) {
|
|
152
|
+
return streamBedrock(model, context, {
|
|
153
|
+
...base,
|
|
154
|
+
reasoning: options.reasoning,
|
|
155
|
+
thinkingBudgets: options.thinkingBudgets,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const adjusted = adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options.thinkingBudgets);
|
|
159
|
+
return streamBedrock(model, context, {
|
|
160
|
+
...base,
|
|
161
|
+
maxTokens: adjusted.maxTokens,
|
|
162
|
+
reasoning: options.reasoning,
|
|
163
|
+
thinkingBudgets: {
|
|
164
|
+
...(options.thinkingBudgets || {}),
|
|
165
|
+
[clampReasoning(options.reasoning)]: adjusted.thinkingBudget,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return streamBedrock(model, context, {
|
|
170
|
+
...base,
|
|
171
|
+
reasoning: options.reasoning,
|
|
172
|
+
thinkingBudgets: options.thinkingBudgets,
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
function handleContentBlockStart(event, blocks, output, stream) {
|
|
176
|
+
const index = event.contentBlockIndex;
|
|
177
|
+
const start = event.start;
|
|
178
|
+
if (start?.toolUse) {
|
|
179
|
+
const block = {
|
|
180
|
+
type: "toolCall",
|
|
181
|
+
id: start.toolUse.toolUseId || "",
|
|
182
|
+
name: start.toolUse.name || "",
|
|
183
|
+
arguments: {},
|
|
184
|
+
partialJson: "",
|
|
185
|
+
index,
|
|
186
|
+
};
|
|
187
|
+
output.content.push(block);
|
|
188
|
+
stream.push({ type: "toolcall_start", contentIndex: blocks.length - 1, partial: output });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function handleContentBlockDelta(event, blocks, output, stream) {
|
|
192
|
+
const contentBlockIndex = event.contentBlockIndex;
|
|
193
|
+
const delta = event.delta;
|
|
194
|
+
let index = blocks.findIndex((b) => b.index === contentBlockIndex);
|
|
195
|
+
let block = blocks[index];
|
|
196
|
+
if (delta?.text !== undefined) {
|
|
197
|
+
if (!block) {
|
|
198
|
+
const newBlock = { type: "text", text: "", index: contentBlockIndex };
|
|
199
|
+
output.content.push(newBlock);
|
|
200
|
+
index = blocks.length - 1;
|
|
201
|
+
block = blocks[index];
|
|
202
|
+
stream.push({ type: "text_start", contentIndex: index, partial: output });
|
|
203
|
+
}
|
|
204
|
+
if (block.type === "text") {
|
|
205
|
+
block.text += delta.text;
|
|
206
|
+
stream.push({ type: "text_delta", contentIndex: index, delta: delta.text, partial: output });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (delta?.toolUse && block?.type === "toolCall") {
|
|
210
|
+
block.partialJson = (block.partialJson || "") + (delta.toolUse.input || "");
|
|
211
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
212
|
+
stream.push({ type: "toolcall_delta", contentIndex: index, delta: delta.toolUse.input || "", partial: output });
|
|
213
|
+
}
|
|
214
|
+
else if (delta?.reasoningContent) {
|
|
215
|
+
let thinkingBlock = block;
|
|
216
|
+
let thinkingIndex = index;
|
|
217
|
+
if (!thinkingBlock) {
|
|
218
|
+
const newBlock = { type: "thinking", thinking: "", thinkingSignature: "", index: contentBlockIndex };
|
|
219
|
+
output.content.push(newBlock);
|
|
220
|
+
thinkingIndex = blocks.length - 1;
|
|
221
|
+
thinkingBlock = blocks[thinkingIndex];
|
|
222
|
+
stream.push({ type: "thinking_start", contentIndex: thinkingIndex, partial: output });
|
|
223
|
+
}
|
|
224
|
+
if (thinkingBlock?.type === "thinking") {
|
|
225
|
+
if (delta.reasoningContent.text) {
|
|
226
|
+
thinkingBlock.thinking += delta.reasoningContent.text;
|
|
227
|
+
stream.push({
|
|
228
|
+
type: "thinking_delta",
|
|
229
|
+
contentIndex: thinkingIndex,
|
|
230
|
+
delta: delta.reasoningContent.text,
|
|
231
|
+
partial: output,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (delta.reasoningContent.signature) {
|
|
235
|
+
thinkingBlock.thinkingSignature =
|
|
236
|
+
(thinkingBlock.thinkingSignature || "") + delta.reasoningContent.signature;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function handleMetadata(event, model, output) {
|
|
242
|
+
if (event.usage) {
|
|
243
|
+
output.usage.input = event.usage.inputTokens || 0;
|
|
244
|
+
output.usage.output = event.usage.outputTokens || 0;
|
|
245
|
+
output.usage.cacheRead = event.usage.cacheReadInputTokens || 0;
|
|
246
|
+
output.usage.cacheWrite = event.usage.cacheWriteInputTokens || 0;
|
|
247
|
+
output.usage.totalTokens = event.usage.totalTokens || output.usage.input + output.usage.output;
|
|
248
|
+
calculateCost(model, output.usage);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function handleContentBlockStop(event, blocks, output, stream) {
|
|
252
|
+
const index = blocks.findIndex((b) => b.index === event.contentBlockIndex);
|
|
253
|
+
const block = blocks[index];
|
|
254
|
+
if (!block)
|
|
255
|
+
return;
|
|
256
|
+
delete block.index;
|
|
257
|
+
switch (block.type) {
|
|
258
|
+
case "text":
|
|
259
|
+
stream.push({ type: "text_end", contentIndex: index, content: block.text, partial: output });
|
|
260
|
+
break;
|
|
261
|
+
case "thinking":
|
|
262
|
+
stream.push({ type: "thinking_end", contentIndex: index, content: block.thinking, partial: output });
|
|
263
|
+
break;
|
|
264
|
+
case "toolCall":
|
|
265
|
+
block.arguments = parseStreamingJson(block.partialJson);
|
|
266
|
+
delete block.partialJson;
|
|
267
|
+
stream.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: output });
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function supportsAdaptiveThinking(modelId) {
|
|
272
|
+
return (modelId.includes("opus-4-6") ||
|
|
273
|
+
modelId.includes("opus-4.6") ||
|
|
274
|
+
modelId.includes("sonnet-4-6") ||
|
|
275
|
+
modelId.includes("sonnet-4.6"));
|
|
276
|
+
}
|
|
277
|
+
function mapThinkingLevelToEffort(level, modelId) {
|
|
278
|
+
switch (level) {
|
|
279
|
+
case "minimal":
|
|
280
|
+
case "low":
|
|
281
|
+
return "low";
|
|
282
|
+
case "medium":
|
|
283
|
+
return "medium";
|
|
284
|
+
case "high":
|
|
285
|
+
return "high";
|
|
286
|
+
case "xhigh":
|
|
287
|
+
return modelId.includes("opus-4-6") || modelId.includes("opus-4.6") ? "max" : "high";
|
|
288
|
+
default:
|
|
289
|
+
return "high";
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function resolveCacheRetention(cacheRetention) {
|
|
293
|
+
if (cacheRetention) {
|
|
294
|
+
return cacheRetention;
|
|
295
|
+
}
|
|
296
|
+
if (typeof process !== "undefined" && process.env.PI_CACHE_RETENTION === "long") {
|
|
297
|
+
return "long";
|
|
298
|
+
}
|
|
299
|
+
return "short";
|
|
300
|
+
}
|
|
301
|
+
function supportsPromptCaching(model) {
|
|
302
|
+
if (model.cost.cacheRead || model.cost.cacheWrite) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
const id = model.id.toLowerCase();
|
|
306
|
+
if (id.includes("claude") && (id.includes("-4-") || id.includes("-4.")))
|
|
307
|
+
return true;
|
|
308
|
+
if (id.includes("claude-3-7-sonnet"))
|
|
309
|
+
return true;
|
|
310
|
+
if (id.includes("claude-3-5-haiku"))
|
|
311
|
+
return true;
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
function supportsThinkingSignature(model) {
|
|
315
|
+
const id = model.id.toLowerCase();
|
|
316
|
+
return id.includes("anthropic.claude") || id.includes("anthropic/claude");
|
|
317
|
+
}
|
|
318
|
+
function buildSystemPrompt(systemPrompt, model, cacheRetention) {
|
|
319
|
+
if (!systemPrompt)
|
|
320
|
+
return undefined;
|
|
321
|
+
const blocks = [{ text: sanitizeSurrogates(systemPrompt) }];
|
|
322
|
+
if (cacheRetention !== "none" && supportsPromptCaching(model)) {
|
|
323
|
+
blocks.push({
|
|
324
|
+
cachePoint: { type: CachePointType.DEFAULT, ...(cacheRetention === "long" ? { ttl: CacheTTL.ONE_HOUR } : {}) },
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return blocks;
|
|
328
|
+
}
|
|
329
|
+
function normalizeToolCallId(id) {
|
|
330
|
+
const sanitized = id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
331
|
+
return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;
|
|
332
|
+
}
|
|
333
|
+
function convertMessages(context, model, cacheRetention) {
|
|
334
|
+
const result = [];
|
|
335
|
+
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
336
|
+
for (let i = 0; i < transformedMessages.length; i++) {
|
|
337
|
+
const m = transformedMessages[i];
|
|
338
|
+
switch (m.role) {
|
|
339
|
+
case "user":
|
|
340
|
+
result.push({
|
|
341
|
+
role: ConversationRole.USER,
|
|
342
|
+
content: typeof m.content === "string"
|
|
343
|
+
? [{ text: sanitizeSurrogates(m.content) }]
|
|
344
|
+
: m.content.map((c) => {
|
|
345
|
+
switch (c.type) {
|
|
346
|
+
case "text":
|
|
347
|
+
return { text: sanitizeSurrogates(c.text) };
|
|
348
|
+
case "image":
|
|
349
|
+
return { image: createImageBlock(c.mimeType, c.data) };
|
|
350
|
+
default:
|
|
351
|
+
throw new Error("Unknown user content type");
|
|
352
|
+
}
|
|
353
|
+
}),
|
|
354
|
+
});
|
|
355
|
+
break;
|
|
356
|
+
case "assistant": {
|
|
357
|
+
if (m.content.length === 0) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const contentBlocks = [];
|
|
361
|
+
for (const c of m.content) {
|
|
362
|
+
switch (c.type) {
|
|
363
|
+
case "text":
|
|
364
|
+
if (c.text.trim().length === 0)
|
|
365
|
+
continue;
|
|
366
|
+
contentBlocks.push({ text: sanitizeSurrogates(c.text) });
|
|
367
|
+
break;
|
|
368
|
+
case "toolCall":
|
|
369
|
+
contentBlocks.push({
|
|
370
|
+
toolUse: { toolUseId: c.id, name: c.name, input: c.arguments },
|
|
371
|
+
});
|
|
372
|
+
break;
|
|
373
|
+
case "thinking":
|
|
374
|
+
if (c.thinking.trim().length === 0)
|
|
375
|
+
continue;
|
|
376
|
+
if (supportsThinkingSignature(model)) {
|
|
377
|
+
contentBlocks.push({
|
|
378
|
+
reasoningContent: {
|
|
379
|
+
reasoningText: { text: sanitizeSurrogates(c.thinking), signature: c.thinkingSignature },
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
contentBlocks.push({
|
|
385
|
+
reasoningContent: {
|
|
386
|
+
reasoningText: { text: sanitizeSurrogates(c.thinking) },
|
|
387
|
+
},
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
break;
|
|
391
|
+
default:
|
|
392
|
+
throw new Error("Unknown assistant content type");
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (contentBlocks.length === 0) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
result.push({
|
|
399
|
+
role: ConversationRole.ASSISTANT,
|
|
400
|
+
content: contentBlocks,
|
|
401
|
+
});
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
case "toolResult": {
|
|
405
|
+
const toolResults = [];
|
|
406
|
+
toolResults.push({
|
|
407
|
+
toolResult: {
|
|
408
|
+
toolUseId: m.toolCallId,
|
|
409
|
+
content: m.content.map((c) => c.type === "image"
|
|
410
|
+
? { image: createImageBlock(c.mimeType, c.data) }
|
|
411
|
+
: { text: sanitizeSurrogates(c.text) }),
|
|
412
|
+
status: m.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
let j = i + 1;
|
|
416
|
+
while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
|
|
417
|
+
const nextMsg = transformedMessages[j];
|
|
418
|
+
toolResults.push({
|
|
419
|
+
toolResult: {
|
|
420
|
+
toolUseId: nextMsg.toolCallId,
|
|
421
|
+
content: nextMsg.content.map((c) => c.type === "image"
|
|
422
|
+
? { image: createImageBlock(c.mimeType, c.data) }
|
|
423
|
+
: { text: sanitizeSurrogates(c.text) }),
|
|
424
|
+
status: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
j++;
|
|
428
|
+
}
|
|
429
|
+
i = j - 1;
|
|
430
|
+
result.push({
|
|
431
|
+
role: ConversationRole.USER,
|
|
432
|
+
content: toolResults,
|
|
433
|
+
});
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
default:
|
|
437
|
+
throw new Error("Unknown message role");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (cacheRetention !== "none" && supportsPromptCaching(model) && result.length > 0) {
|
|
441
|
+
const lastMessage = result[result.length - 1];
|
|
442
|
+
if (lastMessage.role === ConversationRole.USER && lastMessage.content) {
|
|
443
|
+
lastMessage.content.push({
|
|
444
|
+
cachePoint: {
|
|
445
|
+
type: CachePointType.DEFAULT,
|
|
446
|
+
...(cacheRetention === "long" ? { ttl: CacheTTL.ONE_HOUR } : {}),
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
function convertToolConfig(tools, toolChoice) {
|
|
454
|
+
if (!tools?.length || toolChoice === "none")
|
|
455
|
+
return undefined;
|
|
456
|
+
const bedrockTools = tools.map((tool) => ({
|
|
457
|
+
toolSpec: {
|
|
458
|
+
name: tool.name,
|
|
459
|
+
description: tool.description,
|
|
460
|
+
inputSchema: { json: tool.parameters },
|
|
461
|
+
},
|
|
462
|
+
}));
|
|
463
|
+
let bedrockToolChoice;
|
|
464
|
+
switch (toolChoice) {
|
|
465
|
+
case "auto":
|
|
466
|
+
bedrockToolChoice = { auto: {} };
|
|
467
|
+
break;
|
|
468
|
+
case "any":
|
|
469
|
+
bedrockToolChoice = { any: {} };
|
|
470
|
+
break;
|
|
471
|
+
default:
|
|
472
|
+
if (toolChoice?.type === "tool") {
|
|
473
|
+
bedrockToolChoice = { tool: { name: toolChoice.name } };
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return { tools: bedrockTools, toolChoice: bedrockToolChoice };
|
|
477
|
+
}
|
|
478
|
+
function mapStopReason(reason) {
|
|
479
|
+
switch (reason) {
|
|
480
|
+
case BedrockStopReason.END_TURN:
|
|
481
|
+
case BedrockStopReason.STOP_SEQUENCE:
|
|
482
|
+
return "stop";
|
|
483
|
+
case BedrockStopReason.MAX_TOKENS:
|
|
484
|
+
case BedrockStopReason.MODEL_CONTEXT_WINDOW_EXCEEDED:
|
|
485
|
+
return "length";
|
|
486
|
+
case BedrockStopReason.TOOL_USE:
|
|
487
|
+
return "toolUse";
|
|
488
|
+
default:
|
|
489
|
+
return "error";
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function buildAdditionalModelRequestFields(model, options) {
|
|
493
|
+
if (!options.reasoning || !model.reasoning) {
|
|
494
|
+
return undefined;
|
|
495
|
+
}
|
|
496
|
+
if (model.id.includes("anthropic.claude") || model.id.includes("anthropic/claude")) {
|
|
497
|
+
const result = supportsAdaptiveThinking(model.id)
|
|
498
|
+
? {
|
|
499
|
+
thinking: { type: "adaptive" },
|
|
500
|
+
output_config: { effort: mapThinkingLevelToEffort(options.reasoning, model.id) },
|
|
501
|
+
}
|
|
502
|
+
: (() => {
|
|
503
|
+
const defaultBudgets = {
|
|
504
|
+
minimal: 1024,
|
|
505
|
+
low: 2048,
|
|
506
|
+
medium: 8192,
|
|
507
|
+
high: 16384,
|
|
508
|
+
xhigh: 16384,
|
|
509
|
+
};
|
|
510
|
+
const level = options.reasoning === "xhigh" ? "high" : options.reasoning;
|
|
511
|
+
const budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning];
|
|
512
|
+
return {
|
|
513
|
+
thinking: {
|
|
514
|
+
type: "enabled",
|
|
515
|
+
budget_tokens: budget,
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
})();
|
|
519
|
+
if (!supportsAdaptiveThinking(model.id) && (options.interleavedThinking ?? true)) {
|
|
520
|
+
result.anthropic_beta = ["interleaved-thinking-2025-05-14"];
|
|
521
|
+
}
|
|
522
|
+
return result;
|
|
523
|
+
}
|
|
524
|
+
return undefined;
|
|
525
|
+
}
|
|
526
|
+
function createImageBlock(mimeType, data) {
|
|
527
|
+
let format;
|
|
528
|
+
switch (mimeType) {
|
|
529
|
+
case "image/jpeg":
|
|
530
|
+
case "image/jpg":
|
|
531
|
+
format = ImageFormat.JPEG;
|
|
532
|
+
break;
|
|
533
|
+
case "image/png":
|
|
534
|
+
format = ImageFormat.PNG;
|
|
535
|
+
break;
|
|
536
|
+
case "image/gif":
|
|
537
|
+
format = ImageFormat.GIF;
|
|
538
|
+
break;
|
|
539
|
+
case "image/webp":
|
|
540
|
+
format = ImageFormat.WEBP;
|
|
541
|
+
break;
|
|
542
|
+
default:
|
|
543
|
+
throw new Error(`Unknown image type: ${mimeType}`);
|
|
544
|
+
}
|
|
545
|
+
const binaryString = atob(data);
|
|
546
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
547
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
548
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
549
|
+
}
|
|
550
|
+
return { source: { bytes }, format };
|
|
551
|
+
}
|
|
552
|
+
//# sourceMappingURL=amazon-bedrock.js.map
|