promptfoo 0.119.13 → 0.119.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +28 -26
- package/dist/src/app/assets/index-eJ2lMe94.js +51 -0
- package/dist/src/app/assets/{source-map-support-Bnh0UQ2S.js → source-map-support-1v4oeb7P.js} +1 -1
- package/dist/src/app/assets/sync-CtLQRuC1.js +1 -0
- package/dist/src/app/assets/{vendor-charts-T60Uk0Z3.js → vendor-charts-DnVv66VV.js} +1 -1
- package/dist/src/app/assets/{vendor-markdown-DLig-KJh.js → vendor-markdown-DCpQIyMA.js} +1 -1
- package/dist/src/app/assets/{vendor-mui-core-5BLaiG3c.js → vendor-mui-core-Boqnpf9f.js} +1 -1
- package/dist/src/app/assets/{vendor-mui-icons-fn39Fu2e.js → vendor-mui-icons-B8MqoVbj.js} +1 -1
- package/dist/src/app/assets/vendor-mui-x-CGSS6QHF.js +45 -0
- package/dist/src/app/assets/{vendor-utils-DYBMEuwX.js → vendor-utils-DdfHIEy8.js} +1 -1
- package/dist/src/app/index.html +7 -7
- package/dist/src/assertions/guardrails.d.ts +1 -1
- package/dist/src/assertions/guardrails.js +18 -9
- package/dist/src/assertions/index.d.ts +1 -1
- package/dist/src/assertions/index.js +9 -3
- package/dist/src/assertions/searchRubric.d.ts +3 -0
- package/dist/src/assertions/searchRubric.js +18 -0
- package/dist/src/commands/eval.js +1 -1
- package/dist/src/commands/modelScan.d.ts +7 -1
- package/dist/src/commands/modelScan.js +121 -59
- package/dist/src/database/index.d.ts +6 -0
- package/dist/src/database/index.js +11 -0
- package/dist/src/database/tables.d.ts +46 -24
- package/dist/src/envars.d.ts +17 -0
- package/dist/src/generated/constants.js +1 -1
- package/dist/src/logger.d.ts +5 -0
- package/dist/src/logger.js +28 -0
- package/dist/src/main.js +17 -6
- package/dist/src/matchers.d.ts +1 -0
- package/dist/src/matchers.js +80 -0
- package/dist/src/models/eval.d.ts +2 -1
- package/dist/src/models/eval.js +44 -2
- package/dist/src/prompts/grading.d.ts +1 -0
- package/dist/src/prompts/grading.js +26 -1
- package/dist/src/prompts/index.d.ts +1 -0
- package/dist/src/prompts/index.js +4 -1
- package/dist/src/providers/adaline.gateway.js +2 -2
- package/dist/src/providers/anthropic/defaults.d.ts +1 -1
- package/dist/src/providers/anthropic/defaults.js +15 -0
- package/dist/src/providers/azure/chat.d.ts +3 -1
- package/dist/src/providers/azure/chat.js +16 -3
- package/dist/src/providers/azure/defaults.js +660 -141
- package/dist/src/providers/azure/responses.d.ts +5 -0
- package/dist/src/providers/azure/responses.js +33 -4
- package/dist/src/providers/azure/types.d.ts +4 -0
- package/dist/src/providers/bedrock/agents.d.ts +1 -1
- package/dist/src/providers/bedrock/agents.js +2 -2
- package/dist/src/providers/bedrock/base.d.ts +40 -0
- package/dist/src/providers/bedrock/base.js +171 -0
- package/dist/src/providers/bedrock/converse.d.ts +146 -0
- package/dist/src/providers/bedrock/converse.js +1044 -0
- package/dist/src/providers/bedrock/index.d.ts +1 -34
- package/dist/src/providers/bedrock/index.js +4 -159
- package/dist/src/providers/bedrock/knowledgeBase.d.ts +1 -1
- package/dist/src/providers/bedrock/knowledgeBase.js +2 -2
- package/dist/src/providers/bedrock/nova-sonic.d.ts +2 -1
- package/dist/src/providers/bedrock/nova-sonic.js +2 -2
- package/dist/src/providers/claude-agent-sdk.d.ts +58 -1
- package/dist/src/providers/claude-agent-sdk.js +22 -1
- package/dist/src/providers/defaults.js +4 -0
- package/dist/src/providers/github/defaults.js +6 -6
- package/dist/src/providers/google/types.d.ts +25 -0
- package/dist/src/providers/google/util.d.ts +2 -0
- package/dist/src/providers/google/vertex.js +78 -22
- package/dist/src/providers/{groq.d.ts → groq/chat.d.ts} +26 -20
- package/dist/src/providers/groq/chat.js +79 -0
- package/dist/src/providers/groq/index.d.ts +5 -0
- package/dist/src/providers/groq/index.js +24 -0
- package/dist/src/providers/groq/responses.d.ts +106 -0
- package/dist/src/providers/groq/responses.js +64 -0
- package/dist/src/providers/groq/types.d.ts +44 -0
- package/dist/src/providers/groq/types.js +3 -0
- package/dist/src/providers/groq/util.d.ts +15 -0
- package/dist/src/providers/groq/util.js +28 -0
- package/dist/src/providers/mcp/client.d.ts +8 -0
- package/dist/src/providers/mcp/client.js +60 -10
- package/dist/src/providers/mcp/types.d.ts +21 -0
- package/dist/src/providers/openai/chatkit-pool.d.ts +114 -0
- package/dist/src/providers/openai/chatkit-pool.js +548 -0
- package/dist/src/providers/openai/chatkit-types.d.ts +73 -0
- package/dist/src/providers/openai/chatkit-types.js +3 -0
- package/dist/src/providers/openai/chatkit.d.ts +76 -0
- package/dist/src/providers/openai/chatkit.js +879 -0
- package/dist/src/providers/openai/codex-sdk.d.ts +109 -0
- package/dist/src/providers/openai/codex-sdk.js +346 -0
- package/dist/src/providers/openai/defaults.d.ts +2 -0
- package/dist/src/providers/openai/defaults.js +10 -4
- package/dist/src/providers/registry.js +48 -9
- package/dist/src/providers/responses/types.d.ts +1 -1
- package/dist/src/providers/sagemaker.d.ts +2 -2
- package/dist/src/providers/webSearchUtils.d.ts +17 -0
- package/dist/src/providers/webSearchUtils.js +169 -0
- package/dist/src/providers/xai/chat.d.ts +61 -0
- package/dist/src/providers/xai/chat.js +68 -3
- package/dist/src/providers/xai/responses.d.ts +189 -0
- package/dist/src/providers/xai/responses.js +268 -0
- package/dist/src/redteam/constants/plugins.d.ts +1 -1
- package/dist/src/redteam/constants/plugins.js +1 -1
- package/dist/src/redteam/constants/strategies.d.ts +1 -1
- package/dist/src/redteam/constants/strategies.js +1 -0
- package/dist/src/redteam/plugins/vlguard.d.ts +53 -4
- package/dist/src/redteam/plugins/vlguard.js +362 -46
- package/dist/src/redteam/providers/constants.d.ts +2 -2
- package/dist/src/redteam/providers/constants.js +2 -2
- package/dist/src/redteam/providers/crescendo/index.d.ts +1 -1
- package/dist/src/redteam/providers/crescendo/index.js +5 -3
- package/dist/src/redteam/providers/hydra/index.js +1 -1
- package/dist/src/server/routes/modelAudit.js +4 -4
- package/dist/src/share.js +4 -2
- package/dist/src/telemetry.js +44 -8
- package/dist/src/types/env.d.ts +3 -0
- package/dist/src/types/env.js +1 -0
- package/dist/src/types/index.d.ts +896 -615
- package/dist/src/types/index.js +1 -0
- package/dist/src/types/providers.d.ts +1 -0
- package/dist/src/types/tracing.d.ts +3 -0
- package/dist/src/util/database.d.ts +6 -4
- package/dist/src/util/file.js +6 -4
- package/dist/src/util/modelAuditCliParser.d.ts +4 -4
- package/dist/src/util/xlsx.js +52 -26
- package/dist/src/validators/providers.d.ts +142 -122
- package/dist/src/validators/providers.js +4 -6
- package/dist/src/validators/redteam.d.ts +36 -28
- package/dist/src/validators/redteam.js +9 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +28 -26
- package/dist/drizzle/CLAUDE.md +0 -65
- package/dist/src/app/assets/index-DifT6VGT.js +0 -51
- package/dist/src/app/assets/sync-Oo-W_Rbj.js +0 -1
- package/dist/src/app/assets/vendor-mui-x-C2xF-yiO.js +0 -45
- package/dist/src/providers/groq.js +0 -48
|
@@ -0,0 +1,1044 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AWS Bedrock Converse API Provider
|
|
4
|
+
*
|
|
5
|
+
* This provider implements the AWS Bedrock Converse API, which provides a unified
|
|
6
|
+
* interface for all Bedrock models. It supports:
|
|
7
|
+
* - Extended thinking (reasoning/ultrathink) for Claude models
|
|
8
|
+
* - Tool calling with standardized format
|
|
9
|
+
* - Streaming responses via ConverseStream
|
|
10
|
+
* - Performance configuration (latency optimization, service tiers)
|
|
11
|
+
* - Guardrails integration
|
|
12
|
+
* - Cache token tracking
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
48
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
49
|
+
};
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.AwsBedrockConverseProvider = void 0;
|
|
52
|
+
exports.parseConverseMessages = parseConverseMessages;
|
|
53
|
+
const path_1 = __importDefault(require("path"));
|
|
54
|
+
const cache_1 = require("../../cache");
|
|
55
|
+
const cliState_1 = __importDefault(require("../../cliState"));
|
|
56
|
+
const esm_1 = require("../../esm");
|
|
57
|
+
const envars_1 = require("../../envars");
|
|
58
|
+
const logger_1 = __importDefault(require("../../logger"));
|
|
59
|
+
const telemetry_1 = __importDefault(require("../../telemetry"));
|
|
60
|
+
const fileExtensions_1 = require("../../util/fileExtensions");
|
|
61
|
+
const index_1 = require("../../util/index");
|
|
62
|
+
const base_1 = require("./base");
|
|
63
|
+
/**
|
|
64
|
+
* Bedrock model pricing per 1M tokens
|
|
65
|
+
* Prices as of 2025 - may need updates
|
|
66
|
+
*/
|
|
67
|
+
const BEDROCK_CONVERSE_PRICING = {
|
|
68
|
+
// Claude Opus 4.5
|
|
69
|
+
'anthropic.claude-opus-4-5': { input: 5, output: 25 },
|
|
70
|
+
// Claude Opus 4/4.1
|
|
71
|
+
'anthropic.claude-opus-4': { input: 15, output: 75 },
|
|
72
|
+
// Claude Sonnet 4/4.5
|
|
73
|
+
'anthropic.claude-sonnet-4': { input: 3, output: 15 },
|
|
74
|
+
// Claude Haiku 4.5
|
|
75
|
+
'anthropic.claude-haiku-4': { input: 1, output: 5 },
|
|
76
|
+
// Claude 3.x
|
|
77
|
+
'anthropic.claude-3-opus': { input: 15, output: 75 },
|
|
78
|
+
'anthropic.claude-3-5-sonnet': { input: 3, output: 15 },
|
|
79
|
+
'anthropic.claude-3-7-sonnet': { input: 3, output: 15 },
|
|
80
|
+
'anthropic.claude-3-5-haiku': { input: 0.8, output: 4 },
|
|
81
|
+
'anthropic.claude-3-haiku': { input: 0.25, output: 1.25 },
|
|
82
|
+
// Amazon Nova
|
|
83
|
+
'amazon.nova-micro': { input: 0.035, output: 0.14 },
|
|
84
|
+
'amazon.nova-lite': { input: 0.06, output: 0.24 },
|
|
85
|
+
'amazon.nova-pro': { input: 0.8, output: 3.2 },
|
|
86
|
+
'amazon.nova-premier': { input: 2.5, output: 10 },
|
|
87
|
+
// Amazon Titan Text
|
|
88
|
+
'amazon.titan-text-lite': { input: 0.15, output: 0.2 },
|
|
89
|
+
'amazon.titan-text-express': { input: 0.8, output: 1.6 },
|
|
90
|
+
'amazon.titan-text-premier': { input: 0.5, output: 1.5 },
|
|
91
|
+
// Meta Llama
|
|
92
|
+
'meta.llama3-1-8b': { input: 0.22, output: 0.22 },
|
|
93
|
+
'meta.llama3-1-70b': { input: 0.99, output: 0.99 },
|
|
94
|
+
'meta.llama3-1-405b': { input: 5.32, output: 16 },
|
|
95
|
+
'meta.llama3-2-1b': { input: 0.1, output: 0.1 },
|
|
96
|
+
'meta.llama3-2-3b': { input: 0.15, output: 0.15 },
|
|
97
|
+
'meta.llama3-2-11b': { input: 0.35, output: 0.35 },
|
|
98
|
+
'meta.llama3-2-90b': { input: 2.0, output: 2.0 },
|
|
99
|
+
'meta.llama3-3-70b': { input: 0.99, output: 0.99 },
|
|
100
|
+
'meta.llama4-scout': { input: 0.17, output: 0.68 },
|
|
101
|
+
'meta.llama4-maverick': { input: 0.17, output: 0.68 },
|
|
102
|
+
'meta.llama4': { input: 1.0, output: 3.0 },
|
|
103
|
+
// Mistral
|
|
104
|
+
'mistral.mistral-7b': { input: 0.15, output: 0.2 },
|
|
105
|
+
'mistral.mixtral-8x7b': { input: 0.45, output: 0.7 },
|
|
106
|
+
'mistral.mistral-large': { input: 4, output: 12 },
|
|
107
|
+
'mistral.mistral-small': { input: 1, output: 3 },
|
|
108
|
+
'mistral.pixtral-large': { input: 2, output: 6 },
|
|
109
|
+
// AI21 Jamba
|
|
110
|
+
'ai21.jamba-1-5-mini': { input: 0.2, output: 0.4 },
|
|
111
|
+
'ai21.jamba-1-5-large': { input: 2, output: 8 },
|
|
112
|
+
// Cohere
|
|
113
|
+
'cohere.command-r': { input: 0.5, output: 1.5 },
|
|
114
|
+
'cohere.command-r-plus': { input: 3, output: 15 },
|
|
115
|
+
// DeepSeek
|
|
116
|
+
'deepseek.deepseek-r1': { input: 1.35, output: 5.4 },
|
|
117
|
+
'deepseek.r1': { input: 1.35, output: 5.4 },
|
|
118
|
+
// Qwen
|
|
119
|
+
'qwen.qwen3-32b': { input: 0.2, output: 0.6 },
|
|
120
|
+
'qwen.qwen3-235b': { input: 0.18, output: 0.54 },
|
|
121
|
+
'qwen.qwen3-coder-30b': { input: 0.2, output: 0.6 },
|
|
122
|
+
'qwen.qwen3-coder-480b': { input: 1.5, output: 7.5 },
|
|
123
|
+
'qwen.qwen3': { input: 0.5, output: 1.5 },
|
|
124
|
+
// Writer Palmyra
|
|
125
|
+
'writer.palmyra-x5': { input: 0.6, output: 6 },
|
|
126
|
+
'writer.palmyra-x4': { input: 2.5, output: 10 },
|
|
127
|
+
// OpenAI GPT-OSS
|
|
128
|
+
'openai.gpt-oss-120b': { input: 1.0, output: 3.0 },
|
|
129
|
+
'openai.gpt-oss-20b': { input: 0.3, output: 0.9 },
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Calculate cost based on model and token usage
|
|
133
|
+
*/
|
|
134
|
+
function calculateBedrockConverseCost(modelId, promptTokens, completionTokens) {
|
|
135
|
+
if (promptTokens === undefined || completionTokens === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
// Find matching pricing
|
|
139
|
+
const normalizedModelId = modelId.toLowerCase();
|
|
140
|
+
for (const [modelPrefix, pricing] of Object.entries(BEDROCK_CONVERSE_PRICING)) {
|
|
141
|
+
if (normalizedModelId.includes(modelPrefix)) {
|
|
142
|
+
const inputCost = (promptTokens / 1000000) * pricing.input;
|
|
143
|
+
const outputCost = (completionTokens / 1000000) * pricing.output;
|
|
144
|
+
return inputCost + outputCost;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Convert various tool formats to Converse API format
|
|
151
|
+
*/
|
|
152
|
+
function convertToolsToConverseFormat(tools) {
|
|
153
|
+
return tools.map((tool) => {
|
|
154
|
+
// Already in Converse format - cast to expected type
|
|
155
|
+
if (tool.toolSpec) {
|
|
156
|
+
return { toolSpec: tool.toolSpec };
|
|
157
|
+
}
|
|
158
|
+
// OpenAI-compatible format
|
|
159
|
+
if (tool.type === 'function' && tool.function) {
|
|
160
|
+
return {
|
|
161
|
+
toolSpec: {
|
|
162
|
+
name: tool.function.name,
|
|
163
|
+
description: tool.function.description,
|
|
164
|
+
inputSchema: {
|
|
165
|
+
json: (tool.function.parameters || {}),
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Anthropic format
|
|
171
|
+
if (tool.name) {
|
|
172
|
+
return {
|
|
173
|
+
toolSpec: {
|
|
174
|
+
name: tool.name,
|
|
175
|
+
description: tool.description,
|
|
176
|
+
inputSchema: {
|
|
177
|
+
json: (tool.input_schema || {}),
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
throw new Error(`Invalid tool configuration: ${JSON.stringify(tool)}`);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Convert tool choice to Converse API format
|
|
187
|
+
*/
|
|
188
|
+
function convertToolChoiceToConverseFormat(toolChoice) {
|
|
189
|
+
if (toolChoice === 'auto') {
|
|
190
|
+
return { auto: {} };
|
|
191
|
+
}
|
|
192
|
+
if (toolChoice === 'any') {
|
|
193
|
+
return { any: {} };
|
|
194
|
+
}
|
|
195
|
+
if (typeof toolChoice === 'object' && toolChoice.tool) {
|
|
196
|
+
return { tool: { name: toolChoice.tool.name } };
|
|
197
|
+
}
|
|
198
|
+
return { auto: {} };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Parse prompt into Converse API message format
|
|
202
|
+
*/
|
|
203
|
+
function parseConverseMessages(prompt) {
|
|
204
|
+
// Try to parse as JSON first
|
|
205
|
+
try {
|
|
206
|
+
const parsed = JSON.parse(prompt);
|
|
207
|
+
if (Array.isArray(parsed)) {
|
|
208
|
+
const systemMessages = [];
|
|
209
|
+
const messages = [];
|
|
210
|
+
for (const msg of parsed) {
|
|
211
|
+
if (msg.role === 'system') {
|
|
212
|
+
// System messages go to the system field
|
|
213
|
+
const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
214
|
+
systemMessages.push({ text: content });
|
|
215
|
+
}
|
|
216
|
+
else if (msg.role === 'user' || msg.role === 'assistant') {
|
|
217
|
+
// Convert content to ContentBlock format
|
|
218
|
+
const contentBlocks = [];
|
|
219
|
+
if (typeof msg.content === 'string') {
|
|
220
|
+
contentBlocks.push({ text: msg.content });
|
|
221
|
+
}
|
|
222
|
+
else if (Array.isArray(msg.content)) {
|
|
223
|
+
for (const block of msg.content) {
|
|
224
|
+
if (typeof block === 'string') {
|
|
225
|
+
contentBlocks.push({ text: block });
|
|
226
|
+
}
|
|
227
|
+
else if (block.type === 'text') {
|
|
228
|
+
contentBlocks.push({ text: block.text });
|
|
229
|
+
}
|
|
230
|
+
else if (block.type === 'image' || block.image) {
|
|
231
|
+
// Handle image content - multiple formats supported
|
|
232
|
+
const imageData = block.image || block;
|
|
233
|
+
let bytes;
|
|
234
|
+
let format = 'png';
|
|
235
|
+
// Determine format from various sources
|
|
236
|
+
if (imageData.format) {
|
|
237
|
+
format = imageData.format;
|
|
238
|
+
}
|
|
239
|
+
else if (imageData.source?.media_type) {
|
|
240
|
+
format = imageData.source.media_type.split('/')[1] || 'png';
|
|
241
|
+
}
|
|
242
|
+
// Get bytes from various sources
|
|
243
|
+
if (imageData.source?.bytes) {
|
|
244
|
+
const rawBytes = imageData.source.bytes;
|
|
245
|
+
if (typeof rawBytes === 'string') {
|
|
246
|
+
// Check for data URL format: data:image/jpeg;base64,...
|
|
247
|
+
if (rawBytes.startsWith('data:')) {
|
|
248
|
+
const matches = rawBytes.match(/^data:image\/([^;]+);base64,(.+)$/);
|
|
249
|
+
if (matches) {
|
|
250
|
+
format = matches[1] === 'jpg' ? 'jpeg' : matches[1];
|
|
251
|
+
bytes = Buffer.from(matches[2], 'base64');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// Assume raw base64 string
|
|
256
|
+
bytes = Buffer.from(rawBytes, 'base64');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else if (Buffer.isBuffer(rawBytes)) {
|
|
260
|
+
bytes = rawBytes;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else if (imageData.source?.data) {
|
|
264
|
+
// Anthropic format: {source: {type: 'base64', media_type: '...', data: '...'}}
|
|
265
|
+
bytes = Buffer.from(imageData.source.data, 'base64');
|
|
266
|
+
}
|
|
267
|
+
if (bytes) {
|
|
268
|
+
// Normalize format names for Converse API
|
|
269
|
+
if (format === 'jpg') {
|
|
270
|
+
format = 'jpeg';
|
|
271
|
+
}
|
|
272
|
+
contentBlocks.push({
|
|
273
|
+
image: {
|
|
274
|
+
format: format,
|
|
275
|
+
source: { bytes },
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
logger_1.default.warn('Could not parse image content block', { block });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else if (block.type === 'image_url' || block.image_url) {
|
|
284
|
+
// OpenAI-compatible image_url format
|
|
285
|
+
const imageUrl = block.image_url?.url || block.url;
|
|
286
|
+
if (typeof imageUrl === 'string' && imageUrl.startsWith('data:')) {
|
|
287
|
+
const matches = imageUrl.match(/^data:image\/([^;]+);base64,(.+)$/);
|
|
288
|
+
if (matches) {
|
|
289
|
+
const format = matches[1] === 'jpg' ? 'jpeg' : matches[1];
|
|
290
|
+
const bytes = Buffer.from(matches[2], 'base64');
|
|
291
|
+
contentBlocks.push({
|
|
292
|
+
image: {
|
|
293
|
+
format: format,
|
|
294
|
+
source: { bytes },
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
logger_1.default.warn('Unsupported image_url format (only data URLs supported)', {
|
|
301
|
+
imageUrl,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else if (block.type === 'document' || block.document) {
|
|
306
|
+
// Handle document content
|
|
307
|
+
const docData = block.document || block;
|
|
308
|
+
let bytes;
|
|
309
|
+
const format = docData.format || 'txt';
|
|
310
|
+
const name = docData.name || 'document';
|
|
311
|
+
if (docData.source?.bytes) {
|
|
312
|
+
const rawBytes = docData.source.bytes;
|
|
313
|
+
if (typeof rawBytes === 'string') {
|
|
314
|
+
// Check for data URL format
|
|
315
|
+
if (rawBytes.startsWith('data:')) {
|
|
316
|
+
const matches = rawBytes.match(/^data:[^;]+;base64,(.+)$/);
|
|
317
|
+
if (matches) {
|
|
318
|
+
bytes = Buffer.from(matches[1], 'base64');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
bytes = Buffer.from(rawBytes, 'base64');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else if (Buffer.isBuffer(rawBytes)) {
|
|
326
|
+
bytes = rawBytes;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (bytes) {
|
|
330
|
+
contentBlocks.push({
|
|
331
|
+
document: {
|
|
332
|
+
format: format,
|
|
333
|
+
name,
|
|
334
|
+
source: { bytes },
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
logger_1.default.warn('Could not parse document content block', { block });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else if (block.type === 'tool_use' || block.toolUse) {
|
|
343
|
+
const toolUseData = block.toolUse || block;
|
|
344
|
+
contentBlocks.push({
|
|
345
|
+
toolUse: {
|
|
346
|
+
toolUseId: toolUseData.toolUseId || toolUseData.id,
|
|
347
|
+
name: toolUseData.name,
|
|
348
|
+
input: toolUseData.input,
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
else if (block.type === 'tool_result' || block.toolResult) {
|
|
353
|
+
const toolResultData = block.toolResult || block;
|
|
354
|
+
contentBlocks.push({
|
|
355
|
+
toolResult: {
|
|
356
|
+
toolUseId: toolResultData.toolUseId || toolResultData.tool_use_id,
|
|
357
|
+
content: Array.isArray(toolResultData.content)
|
|
358
|
+
? toolResultData.content.map((c) => typeof c === 'string' ? { text: c } : c)
|
|
359
|
+
: [{ text: String(toolResultData.content) }],
|
|
360
|
+
status: toolResultData.status,
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
// Unknown block type, try to convert to text
|
|
366
|
+
contentBlocks.push({ text: JSON.stringify(block) });
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
contentBlocks.push({ text: JSON.stringify(msg.content) });
|
|
372
|
+
}
|
|
373
|
+
messages.push({
|
|
374
|
+
role: msg.role,
|
|
375
|
+
content: contentBlocks,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
messages,
|
|
381
|
+
system: systemMessages.length > 0 ? systemMessages : undefined,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
// Not JSON, try line-based parsing
|
|
387
|
+
}
|
|
388
|
+
// Parse as line-based format or plain text
|
|
389
|
+
const lines = prompt.split('\n');
|
|
390
|
+
const messages = [];
|
|
391
|
+
let system;
|
|
392
|
+
let currentRole = null;
|
|
393
|
+
let currentContent = [];
|
|
394
|
+
const pushMessage = () => {
|
|
395
|
+
if (currentRole && currentContent.length > 0) {
|
|
396
|
+
messages.push({
|
|
397
|
+
role: currentRole,
|
|
398
|
+
content: [{ text: currentContent.join('\n') }],
|
|
399
|
+
});
|
|
400
|
+
currentContent = [];
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
for (const line of lines) {
|
|
404
|
+
const trimmedLine = line.trim();
|
|
405
|
+
if (trimmedLine.toLowerCase().startsWith('system:')) {
|
|
406
|
+
pushMessage();
|
|
407
|
+
system = [{ text: trimmedLine.slice(7).trim() }];
|
|
408
|
+
currentRole = null;
|
|
409
|
+
}
|
|
410
|
+
else if (trimmedLine.toLowerCase().startsWith('user:')) {
|
|
411
|
+
pushMessage();
|
|
412
|
+
currentRole = 'user';
|
|
413
|
+
const content = trimmedLine.slice(5).trim();
|
|
414
|
+
if (content) {
|
|
415
|
+
currentContent.push(content);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
else if (trimmedLine.toLowerCase().startsWith('assistant:')) {
|
|
419
|
+
pushMessage();
|
|
420
|
+
currentRole = 'assistant';
|
|
421
|
+
const content = trimmedLine.slice(10).trim();
|
|
422
|
+
if (content) {
|
|
423
|
+
currentContent.push(content);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
else if (currentRole) {
|
|
427
|
+
currentContent.push(line);
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
// No role prefix, treat as user message
|
|
431
|
+
currentRole = 'user';
|
|
432
|
+
currentContent.push(line);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
pushMessage();
|
|
436
|
+
// If no messages were parsed, treat entire prompt as user message
|
|
437
|
+
if (messages.length === 0) {
|
|
438
|
+
messages.push({
|
|
439
|
+
role: 'user',
|
|
440
|
+
content: [{ text: prompt }],
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return { messages, system };
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Extract text output from Converse API response content blocks
|
|
447
|
+
*/
|
|
448
|
+
function extractTextFromContentBlocks(content, showThinking = true) {
|
|
449
|
+
const parts = [];
|
|
450
|
+
for (const block of content) {
|
|
451
|
+
if ('text' in block && block.text) {
|
|
452
|
+
parts.push(block.text);
|
|
453
|
+
}
|
|
454
|
+
else if ('reasoningContent' in block && block.reasoningContent) {
|
|
455
|
+
// Handle extended thinking content
|
|
456
|
+
const reasoning = block.reasoningContent;
|
|
457
|
+
if (showThinking) {
|
|
458
|
+
if ('reasoningText' in reasoning && reasoning.reasoningText) {
|
|
459
|
+
const thinkingText = reasoning.reasoningText.text || '';
|
|
460
|
+
const signature = reasoning.reasoningText.signature || '';
|
|
461
|
+
parts.push(`<thinking>\n${thinkingText}\n</thinking>`);
|
|
462
|
+
if (signature) {
|
|
463
|
+
parts.push(`Signature: ${signature}`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
else if ('redactedContent' in reasoning && reasoning.redactedContent) {
|
|
467
|
+
parts.push('<thinking>[Redacted]</thinking>');
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
else if ('toolUse' in block && block.toolUse) {
|
|
472
|
+
// Format tool use for output
|
|
473
|
+
parts.push(JSON.stringify({
|
|
474
|
+
type: 'tool_use',
|
|
475
|
+
id: block.toolUse.toolUseId,
|
|
476
|
+
name: block.toolUse.name,
|
|
477
|
+
input: block.toolUse.input,
|
|
478
|
+
}));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return parts.join('\n\n');
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* AWS Bedrock Converse API Provider
|
|
485
|
+
*/
|
|
486
|
+
class AwsBedrockConverseProvider extends base_1.AwsBedrockGenericProvider {
|
|
487
|
+
constructor(modelName, options = {}) {
|
|
488
|
+
super(modelName, options);
|
|
489
|
+
this.loadedFunctionCallbacks = {};
|
|
490
|
+
this.config = options.config || {};
|
|
491
|
+
// Record telemetry
|
|
492
|
+
if (this.config.thinking) {
|
|
493
|
+
telemetry_1.default.record('feature_used', {
|
|
494
|
+
feature: 'extended_thinking',
|
|
495
|
+
provider: 'bedrock_converse',
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
if (this.config.tools) {
|
|
499
|
+
telemetry_1.default.record('feature_used', {
|
|
500
|
+
feature: 'tool_use',
|
|
501
|
+
provider: 'bedrock_converse',
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
id() {
|
|
506
|
+
return `bedrock:converse:${this.modelName}`;
|
|
507
|
+
}
|
|
508
|
+
toString() {
|
|
509
|
+
return `[AWS Bedrock Converse Provider ${this.modelName}]`;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Loads a function from an external file
|
|
513
|
+
* @param fileRef The file reference in the format 'file://path/to/file:functionName'
|
|
514
|
+
* @returns The loaded function
|
|
515
|
+
*/
|
|
516
|
+
async loadExternalFunction(fileRef) {
|
|
517
|
+
let filePath = fileRef.slice('file://'.length);
|
|
518
|
+
let functionName;
|
|
519
|
+
if (filePath.includes(':')) {
|
|
520
|
+
const splits = filePath.split(':');
|
|
521
|
+
if (splits[0] && (0, fileExtensions_1.isJavascriptFile)(splits[0])) {
|
|
522
|
+
[filePath, functionName] = splits;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
const resolvedPath = path_1.default.resolve(cliState_1.default.basePath || '', filePath);
|
|
527
|
+
logger_1.default.debug(`[Bedrock Converse] Loading function from ${resolvedPath}${functionName ? `:${functionName}` : ''}`);
|
|
528
|
+
const requiredModule = await (0, esm_1.importModule)(resolvedPath, functionName);
|
|
529
|
+
if (typeof requiredModule === 'function') {
|
|
530
|
+
return requiredModule;
|
|
531
|
+
}
|
|
532
|
+
else if (requiredModule &&
|
|
533
|
+
typeof requiredModule === 'object' &&
|
|
534
|
+
functionName &&
|
|
535
|
+
functionName in requiredModule) {
|
|
536
|
+
const fn = requiredModule[functionName];
|
|
537
|
+
if (typeof fn === 'function') {
|
|
538
|
+
return fn;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
throw new Error(`Function callback malformed: ${filePath} must export ${functionName
|
|
542
|
+
? `a named function '${functionName}'`
|
|
543
|
+
: 'a function or have a default export as a function'}`);
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
throw new Error(`Error loading function from ${filePath}: ${error.message || String(error)}`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Executes a function callback with proper error handling
|
|
551
|
+
*/
|
|
552
|
+
async executeFunctionCallback(functionName, args) {
|
|
553
|
+
try {
|
|
554
|
+
// Check if we've already loaded this function
|
|
555
|
+
let callback = this.loadedFunctionCallbacks[functionName];
|
|
556
|
+
// If not loaded yet, try to load it now
|
|
557
|
+
if (!callback) {
|
|
558
|
+
const callbackRef = this.config.functionToolCallbacks?.[functionName];
|
|
559
|
+
if (callbackRef && typeof callbackRef === 'string') {
|
|
560
|
+
const callbackStr = callbackRef;
|
|
561
|
+
if (callbackStr.startsWith('file://')) {
|
|
562
|
+
callback = await this.loadExternalFunction(callbackStr);
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
callback = new Function('return ' + callbackStr)();
|
|
566
|
+
}
|
|
567
|
+
// Cache for future use
|
|
568
|
+
this.loadedFunctionCallbacks[functionName] = callback;
|
|
569
|
+
}
|
|
570
|
+
else if (typeof callbackRef === 'function') {
|
|
571
|
+
callback = callbackRef;
|
|
572
|
+
this.loadedFunctionCallbacks[functionName] = callback;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (!callback) {
|
|
576
|
+
throw new Error(`No callback found for function '${functionName}'`);
|
|
577
|
+
}
|
|
578
|
+
// Execute the callback
|
|
579
|
+
logger_1.default.debug(`[Bedrock Converse] Executing function '${functionName}' with args: ${args}`);
|
|
580
|
+
const result = await callback(args);
|
|
581
|
+
// Format the result
|
|
582
|
+
if (result === undefined || result === null) {
|
|
583
|
+
return '';
|
|
584
|
+
}
|
|
585
|
+
else if (typeof result === 'object') {
|
|
586
|
+
try {
|
|
587
|
+
return JSON.stringify(result);
|
|
588
|
+
}
|
|
589
|
+
catch (error) {
|
|
590
|
+
logger_1.default.warn(`Error stringifying result from function '${functionName}': ${error}`);
|
|
591
|
+
return String(result);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
return String(result);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
logger_1.default.error(`[Bedrock Converse] Error executing function '${functionName}': ${error.message || String(error)}`);
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Build the inference configuration from options
|
|
605
|
+
*/
|
|
606
|
+
buildInferenceConfig() {
|
|
607
|
+
const maxTokens = this.config.maxTokens ||
|
|
608
|
+
this.config.max_tokens ||
|
|
609
|
+
(0, envars_1.getEnvInt)('AWS_BEDROCK_MAX_TOKENS') ||
|
|
610
|
+
undefined;
|
|
611
|
+
const temperature = this.config.temperature ?? (0, envars_1.getEnvFloat)('AWS_BEDROCK_TEMPERATURE') ?? undefined;
|
|
612
|
+
const topP = this.config.topP || this.config.top_p || (0, envars_1.getEnvFloat)('AWS_BEDROCK_TOP_P');
|
|
613
|
+
let stopSequences = this.config.stopSequences || this.config.stop;
|
|
614
|
+
if (!stopSequences) {
|
|
615
|
+
const envStop = (0, envars_1.getEnvString)('AWS_BEDROCK_STOP');
|
|
616
|
+
if (envStop) {
|
|
617
|
+
try {
|
|
618
|
+
stopSequences = JSON.parse(envStop);
|
|
619
|
+
}
|
|
620
|
+
catch {
|
|
621
|
+
// Ignore invalid JSON
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
// Only return config if at least one field is set
|
|
626
|
+
if (maxTokens !== undefined ||
|
|
627
|
+
temperature !== undefined ||
|
|
628
|
+
topP !== undefined ||
|
|
629
|
+
stopSequences) {
|
|
630
|
+
return {
|
|
631
|
+
...(maxTokens !== undefined ? { maxTokens } : {}),
|
|
632
|
+
...(temperature !== undefined ? { temperature } : {}),
|
|
633
|
+
...(topP !== undefined ? { topP } : {}),
|
|
634
|
+
...(stopSequences ? { stopSequences } : {}),
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
return undefined;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Build the tool configuration from options
|
|
641
|
+
*/
|
|
642
|
+
async buildToolConfig(vars) {
|
|
643
|
+
if (!this.config.tools || this.config.tools.length === 0) {
|
|
644
|
+
return undefined;
|
|
645
|
+
}
|
|
646
|
+
// Load tools from external file with variable rendering if needed
|
|
647
|
+
const tools = await (0, index_1.maybeLoadToolsFromExternalFile)(this.config.tools, vars);
|
|
648
|
+
if (!tools || tools.length === 0) {
|
|
649
|
+
return undefined;
|
|
650
|
+
}
|
|
651
|
+
const converseTools = convertToolsToConverseFormat(tools);
|
|
652
|
+
const toolChoice = this.config.toolChoice
|
|
653
|
+
? convertToolChoiceToConverseFormat(this.config.toolChoice)
|
|
654
|
+
: undefined;
|
|
655
|
+
return {
|
|
656
|
+
tools: converseTools,
|
|
657
|
+
...(toolChoice ? { toolChoice } : {}),
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Build the guardrail configuration
|
|
662
|
+
*/
|
|
663
|
+
buildGuardrailConfig() {
|
|
664
|
+
if (!this.config.guardrailIdentifier) {
|
|
665
|
+
return undefined;
|
|
666
|
+
}
|
|
667
|
+
return {
|
|
668
|
+
guardrailIdentifier: String(this.config.guardrailIdentifier),
|
|
669
|
+
guardrailVersion: String(this.config.guardrailVersion || 'DRAFT'),
|
|
670
|
+
...(this.config.trace ? { trace: this.config.trace } : {}),
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Build additional model request fields (including thinking config)
|
|
675
|
+
*/
|
|
676
|
+
buildAdditionalModelRequestFields() {
|
|
677
|
+
const fields = {
|
|
678
|
+
...(this.config.additionalModelRequestFields || {}),
|
|
679
|
+
};
|
|
680
|
+
// Add thinking configuration for Claude models
|
|
681
|
+
if (this.config.thinking) {
|
|
682
|
+
fields.thinking = this.config.thinking;
|
|
683
|
+
}
|
|
684
|
+
return Object.keys(fields).length > 0 ? fields : undefined;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Build performance configuration
|
|
688
|
+
*/
|
|
689
|
+
buildPerformanceConfig() {
|
|
690
|
+
if (!this.config.performanceConfig) {
|
|
691
|
+
return undefined;
|
|
692
|
+
}
|
|
693
|
+
return {
|
|
694
|
+
latency: this.config.performanceConfig.latency,
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Build service tier configuration
|
|
699
|
+
*/
|
|
700
|
+
buildServiceTier() {
|
|
701
|
+
if (!this.config.serviceTier) {
|
|
702
|
+
return undefined;
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
type: this.config.serviceTier.type,
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Main API call using Converse API
|
|
710
|
+
*/
|
|
711
|
+
async callApi(prompt, context) {
|
|
712
|
+
// Parse the prompt into messages
|
|
713
|
+
const { messages, system } = parseConverseMessages(prompt);
|
|
714
|
+
// Build the request
|
|
715
|
+
const inferenceConfig = this.buildInferenceConfig();
|
|
716
|
+
const toolConfig = await this.buildToolConfig(context?.vars);
|
|
717
|
+
const guardrailConfig = this.buildGuardrailConfig();
|
|
718
|
+
const additionalModelRequestFields = this.buildAdditionalModelRequestFields();
|
|
719
|
+
const performanceConfig = this.buildPerformanceConfig();
|
|
720
|
+
const serviceTier = this.buildServiceTier();
|
|
721
|
+
const converseInput = {
|
|
722
|
+
modelId: this.modelName,
|
|
723
|
+
messages,
|
|
724
|
+
...(system ? { system } : {}),
|
|
725
|
+
...(inferenceConfig ? { inferenceConfig } : {}),
|
|
726
|
+
...(toolConfig ? { toolConfig } : {}),
|
|
727
|
+
...(guardrailConfig ? { guardrailConfig } : {}),
|
|
728
|
+
...(additionalModelRequestFields ? { additionalModelRequestFields } : {}),
|
|
729
|
+
...(this.config.additionalModelResponseFieldPaths
|
|
730
|
+
? { additionalModelResponseFieldPaths: this.config.additionalModelResponseFieldPaths }
|
|
731
|
+
: {}),
|
|
732
|
+
...(performanceConfig ? { performanceConfig } : {}),
|
|
733
|
+
...(serviceTier ? { serviceTier } : {}),
|
|
734
|
+
};
|
|
735
|
+
logger_1.default.debug('Calling AWS Bedrock Converse API', {
|
|
736
|
+
modelId: this.modelName,
|
|
737
|
+
messageCount: messages.length,
|
|
738
|
+
hasSystem: !!system,
|
|
739
|
+
hasTools: !!toolConfig,
|
|
740
|
+
hasThinking: !!this.config.thinking,
|
|
741
|
+
});
|
|
742
|
+
// Check cache
|
|
743
|
+
const cache = await (0, cache_1.getCache)();
|
|
744
|
+
const cacheKey = `bedrock:converse:${this.modelName}:${JSON.stringify(converseInput)}`;
|
|
745
|
+
if ((0, cache_1.isCacheEnabled)()) {
|
|
746
|
+
const cachedResponse = await cache.get(cacheKey);
|
|
747
|
+
if (cachedResponse) {
|
|
748
|
+
logger_1.default.debug('Returning cached response');
|
|
749
|
+
const parsed = JSON.parse(cachedResponse);
|
|
750
|
+
return await this.parseResponse(parsed);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
// Make the API call
|
|
754
|
+
let response;
|
|
755
|
+
try {
|
|
756
|
+
const bedrockInstance = await this.getBedrockInstance();
|
|
757
|
+
// Import and use ConverseCommand
|
|
758
|
+
const { ConverseCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-bedrock-runtime')));
|
|
759
|
+
const command = new ConverseCommand(converseInput);
|
|
760
|
+
response = await bedrockInstance.send(command);
|
|
761
|
+
}
|
|
762
|
+
catch (err) {
|
|
763
|
+
const errorMessage = err?.message || String(err);
|
|
764
|
+
logger_1.default.error('Bedrock Converse API error', { error: errorMessage });
|
|
765
|
+
// Provide helpful error messages for common issues
|
|
766
|
+
if (errorMessage.includes('ValidationException')) {
|
|
767
|
+
return {
|
|
768
|
+
error: `Bedrock Converse API validation error: ${errorMessage}. Check that your model supports the Converse API and all parameters are valid.`,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
if (errorMessage.includes('AccessDeniedException')) {
|
|
772
|
+
return {
|
|
773
|
+
error: `Bedrock access denied: ${errorMessage}. Ensure you have bedrock:InvokeModel permission and model access is enabled.`,
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
return {
|
|
777
|
+
error: `Bedrock Converse API error: ${errorMessage}`,
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
// Cache the response
|
|
781
|
+
if ((0, cache_1.isCacheEnabled)()) {
|
|
782
|
+
try {
|
|
783
|
+
await cache.set(cacheKey, JSON.stringify(response));
|
|
784
|
+
}
|
|
785
|
+
catch (err) {
|
|
786
|
+
logger_1.default.error(`Failed to cache response: ${String(err)}`);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
logger_1.default.debug('Bedrock Converse API response received', {
|
|
790
|
+
stopReason: response.stopReason,
|
|
791
|
+
hasUsage: !!response.usage,
|
|
792
|
+
hasMetrics: !!response.metrics,
|
|
793
|
+
});
|
|
794
|
+
return await this.parseResponse(response);
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Parse the Converse API response into ProviderResponse format
|
|
798
|
+
*/
|
|
799
|
+
async parseResponse(response) {
|
|
800
|
+
// Extract output text
|
|
801
|
+
const outputMessage = response.output?.message;
|
|
802
|
+
const content = outputMessage?.content || [];
|
|
803
|
+
const showThinking = this.config.showThinking !== false;
|
|
804
|
+
// Extract token usage
|
|
805
|
+
const usage = response.usage;
|
|
806
|
+
const promptTokens = usage?.inputTokens;
|
|
807
|
+
const completionTokens = usage?.outputTokens;
|
|
808
|
+
const totalTokens = usage?.totalTokens;
|
|
809
|
+
const cacheReadTokens = usage?.cacheReadInputTokens;
|
|
810
|
+
const cacheWriteTokens = usage?.cacheWriteInputTokens;
|
|
811
|
+
const tokenUsage = {
|
|
812
|
+
prompt: promptTokens,
|
|
813
|
+
completion: completionTokens,
|
|
814
|
+
total: totalTokens || (promptTokens || 0) + (completionTokens || 0),
|
|
815
|
+
numRequests: 1,
|
|
816
|
+
};
|
|
817
|
+
// Calculate cost
|
|
818
|
+
const cost = calculateBedrockConverseCost(this.modelName, promptTokens, completionTokens);
|
|
819
|
+
// Build metadata
|
|
820
|
+
const metadata = {};
|
|
821
|
+
// Add latency
|
|
822
|
+
if (response.metrics?.latencyMs) {
|
|
823
|
+
metadata.latencyMs = response.metrics.latencyMs;
|
|
824
|
+
}
|
|
825
|
+
// Add stop reason
|
|
826
|
+
if (response.stopReason) {
|
|
827
|
+
metadata.stopReason = response.stopReason;
|
|
828
|
+
}
|
|
829
|
+
// Add cache token info
|
|
830
|
+
if (cacheReadTokens !== undefined || cacheWriteTokens !== undefined) {
|
|
831
|
+
metadata.cacheTokens = {
|
|
832
|
+
read: cacheReadTokens,
|
|
833
|
+
write: cacheWriteTokens,
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
// Add performance config info
|
|
837
|
+
if (response.performanceConfig) {
|
|
838
|
+
metadata.performanceConfig = response.performanceConfig;
|
|
839
|
+
}
|
|
840
|
+
// Add service tier info
|
|
841
|
+
if (response.serviceTier) {
|
|
842
|
+
metadata.serviceTier = response.serviceTier;
|
|
843
|
+
}
|
|
844
|
+
// Add additional model response fields
|
|
845
|
+
if (response.additionalModelResponseFields) {
|
|
846
|
+
metadata.additionalModelResponseFields = response.additionalModelResponseFields;
|
|
847
|
+
}
|
|
848
|
+
// Add trace info if present
|
|
849
|
+
if (response.trace) {
|
|
850
|
+
metadata.trace = response.trace;
|
|
851
|
+
}
|
|
852
|
+
// Check for guardrail intervention
|
|
853
|
+
const guardrails = response.stopReason === 'guardrail_intervened'
|
|
854
|
+
? { flagged: true, reason: 'guardrail_intervened' }
|
|
855
|
+
: undefined;
|
|
856
|
+
// Handle function tool callbacks if configured
|
|
857
|
+
if (this.config.functionToolCallbacks) {
|
|
858
|
+
const toolUseBlocks = content.filter((block) => 'toolUse' in block && block.toolUse !== undefined);
|
|
859
|
+
if (toolUseBlocks.length > 0) {
|
|
860
|
+
const results = [];
|
|
861
|
+
let hasSuccessfulCallback = false;
|
|
862
|
+
for (const block of toolUseBlocks) {
|
|
863
|
+
const functionName = block.toolUse.name;
|
|
864
|
+
if (functionName && this.config.functionToolCallbacks[functionName]) {
|
|
865
|
+
try {
|
|
866
|
+
const args = typeof block.toolUse.input === 'string'
|
|
867
|
+
? block.toolUse.input
|
|
868
|
+
: JSON.stringify(block.toolUse.input || {});
|
|
869
|
+
const result = await this.executeFunctionCallback(functionName, args);
|
|
870
|
+
results.push(result);
|
|
871
|
+
hasSuccessfulCallback = true;
|
|
872
|
+
}
|
|
873
|
+
catch (_error) {
|
|
874
|
+
// If callback fails, fall back to original behavior
|
|
875
|
+
logger_1.default.debug(`[Bedrock Converse] Function callback failed for ${functionName}, falling back to tool_use output`);
|
|
876
|
+
hasSuccessfulCallback = false;
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (hasSuccessfulCallback && results.length > 0) {
|
|
882
|
+
return {
|
|
883
|
+
output: results.join('\n'),
|
|
884
|
+
tokenUsage,
|
|
885
|
+
...(cost !== undefined ? { cost } : {}),
|
|
886
|
+
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
887
|
+
...(guardrails ? { guardrails } : {}),
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
// Default output extraction
|
|
893
|
+
const output = extractTextFromContentBlocks(content, showThinking);
|
|
894
|
+
return {
|
|
895
|
+
output,
|
|
896
|
+
tokenUsage,
|
|
897
|
+
...(cost !== undefined ? { cost } : {}),
|
|
898
|
+
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
899
|
+
...(guardrails ? { guardrails } : {}),
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Streaming API call using ConverseStream
|
|
904
|
+
*
|
|
905
|
+
* Note: functionToolCallbacks are not executed in streaming mode.
|
|
906
|
+
* Tool use blocks are captured and returned in the output, but callbacks
|
|
907
|
+
* are not automatically invoked. Use non-streaming mode if you need
|
|
908
|
+
* automatic tool callback execution.
|
|
909
|
+
*/
|
|
910
|
+
async callApiStreaming(prompt, context) {
|
|
911
|
+
// Parse the prompt into messages
|
|
912
|
+
const { messages, system } = parseConverseMessages(prompt);
|
|
913
|
+
// Build the request (same as non-streaming)
|
|
914
|
+
const inferenceConfig = this.buildInferenceConfig();
|
|
915
|
+
const toolConfig = await this.buildToolConfig(context?.vars);
|
|
916
|
+
const guardrailConfig = this.buildGuardrailConfig();
|
|
917
|
+
const additionalModelRequestFields = this.buildAdditionalModelRequestFields();
|
|
918
|
+
const performanceConfig = this.buildPerformanceConfig();
|
|
919
|
+
const serviceTier = this.buildServiceTier();
|
|
920
|
+
const converseStreamInput = {
|
|
921
|
+
modelId: this.modelName,
|
|
922
|
+
messages,
|
|
923
|
+
...(system ? { system } : {}),
|
|
924
|
+
...(inferenceConfig ? { inferenceConfig } : {}),
|
|
925
|
+
...(toolConfig ? { toolConfig } : {}),
|
|
926
|
+
...(guardrailConfig ? { guardrailConfig } : {}),
|
|
927
|
+
...(additionalModelRequestFields ? { additionalModelRequestFields } : {}),
|
|
928
|
+
...(performanceConfig ? { performanceConfig } : {}),
|
|
929
|
+
...(serviceTier ? { serviceTier } : {}),
|
|
930
|
+
};
|
|
931
|
+
logger_1.default.debug('Calling AWS Bedrock ConverseStream API', {
|
|
932
|
+
modelId: this.modelName,
|
|
933
|
+
messageCount: messages.length,
|
|
934
|
+
});
|
|
935
|
+
try {
|
|
936
|
+
const bedrockInstance = await this.getBedrockInstance();
|
|
937
|
+
const { ConverseStreamCommand } = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-bedrock-runtime')));
|
|
938
|
+
const command = new ConverseStreamCommand(converseStreamInput);
|
|
939
|
+
const response = await bedrockInstance.send(command);
|
|
940
|
+
// Collect the full response while also providing a stream
|
|
941
|
+
let output = '';
|
|
942
|
+
let reasoning = '';
|
|
943
|
+
let stopReason;
|
|
944
|
+
let usage = {};
|
|
945
|
+
// Track tool use blocks being streamed
|
|
946
|
+
const toolUseBlocks = new Map();
|
|
947
|
+
const showThinking = this.config.showThinking !== false;
|
|
948
|
+
// Process the stream
|
|
949
|
+
if (response.stream) {
|
|
950
|
+
for await (const event of response.stream) {
|
|
951
|
+
// Handle content block start - includes tool use initialization
|
|
952
|
+
if ('contentBlockStart' in event && event.contentBlockStart) {
|
|
953
|
+
const blockIndex = event.contentBlockStart.contentBlockIndex ?? 0;
|
|
954
|
+
const start = event.contentBlockStart.start;
|
|
955
|
+
if (start && 'toolUse' in start && start.toolUse) {
|
|
956
|
+
toolUseBlocks.set(blockIndex, {
|
|
957
|
+
toolUseId: start.toolUse.toolUseId,
|
|
958
|
+
name: start.toolUse.name,
|
|
959
|
+
input: '',
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if ('contentBlockDelta' in event && event.contentBlockDelta?.delta) {
|
|
964
|
+
const delta = event.contentBlockDelta.delta;
|
|
965
|
+
const blockIndex = event.contentBlockDelta.contentBlockIndex ?? 0;
|
|
966
|
+
if ('text' in delta && delta.text) {
|
|
967
|
+
output += delta.text;
|
|
968
|
+
}
|
|
969
|
+
if ('reasoningContent' in delta && delta.reasoningContent && showThinking) {
|
|
970
|
+
const rc = delta.reasoningContent;
|
|
971
|
+
if (rc.text) {
|
|
972
|
+
reasoning += rc.text;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
// Handle streaming tool use input
|
|
976
|
+
if ('toolUse' in delta && delta.toolUse) {
|
|
977
|
+
const toolBlock = toolUseBlocks.get(blockIndex);
|
|
978
|
+
if (toolBlock && delta.toolUse.input) {
|
|
979
|
+
toolBlock.input += delta.toolUse.input;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if ('messageStop' in event && event.messageStop) {
|
|
984
|
+
stopReason = event.messageStop.stopReason;
|
|
985
|
+
}
|
|
986
|
+
if ('metadata' in event && event.metadata?.usage) {
|
|
987
|
+
usage = event.metadata.usage;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
// Format tool use blocks for output (same as non-streaming)
|
|
992
|
+
const toolUseParts = [];
|
|
993
|
+
for (const [, toolBlock] of toolUseBlocks) {
|
|
994
|
+
if (toolBlock.name) {
|
|
995
|
+
let parsedInput;
|
|
996
|
+
try {
|
|
997
|
+
parsedInput = toolBlock.input ? JSON.parse(toolBlock.input) : {};
|
|
998
|
+
}
|
|
999
|
+
catch {
|
|
1000
|
+
parsedInput = toolBlock.input;
|
|
1001
|
+
}
|
|
1002
|
+
toolUseParts.push(JSON.stringify({
|
|
1003
|
+
type: 'tool_use',
|
|
1004
|
+
id: toolBlock.toolUseId,
|
|
1005
|
+
name: toolBlock.name,
|
|
1006
|
+
input: parsedInput,
|
|
1007
|
+
}));
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
// Combine reasoning, output, and tool use
|
|
1011
|
+
const parts = [];
|
|
1012
|
+
if (reasoning) {
|
|
1013
|
+
parts.push(`<thinking>\n${reasoning}\n</thinking>`);
|
|
1014
|
+
}
|
|
1015
|
+
if (output) {
|
|
1016
|
+
parts.push(output);
|
|
1017
|
+
}
|
|
1018
|
+
if (toolUseParts.length > 0) {
|
|
1019
|
+
parts.push(...toolUseParts);
|
|
1020
|
+
}
|
|
1021
|
+
const finalOutput = parts.join('\n\n');
|
|
1022
|
+
const tokenUsage = {
|
|
1023
|
+
prompt: usage.inputTokens,
|
|
1024
|
+
completion: usage.outputTokens,
|
|
1025
|
+
total: usage.totalTokens || (usage.inputTokens || 0) + (usage.outputTokens || 0),
|
|
1026
|
+
numRequests: 1,
|
|
1027
|
+
};
|
|
1028
|
+
const cost = calculateBedrockConverseCost(this.modelName, usage.inputTokens, usage.outputTokens);
|
|
1029
|
+
return {
|
|
1030
|
+
output: finalOutput,
|
|
1031
|
+
tokenUsage,
|
|
1032
|
+
...(cost !== undefined ? { cost } : {}),
|
|
1033
|
+
...(stopReason ? { metadata: { stopReason } } : {}),
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
catch (err) {
|
|
1037
|
+
return {
|
|
1038
|
+
error: `Bedrock ConverseStream API error: ${err?.message || String(err)}`,
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
exports.AwsBedrockConverseProvider = AwsBedrockConverseProvider;
|
|
1044
|
+
//# sourceMappingURL=converse.js.map
|