@contentgrowth/llm-service 1.2.3 → 1.3.0
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 +232 -0
- package/dist/index.cjs +197 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -15
- package/dist/index.d.ts +65 -15
- package/dist/index.js +197 -70
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/ui/react/components/index.d.cts +2 -3
- package/dist/ui/react/components/index.d.ts +2 -3
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -74,6 +74,7 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
74
74
|
models: MODEL_CONFIGS[tenantConfig.provider],
|
|
75
75
|
// for backward compatibility, api_key is deprecated and shall never be used!!
|
|
76
76
|
apiKey: tenantConfig.apiKey || tenantConfig.api_key,
|
|
77
|
+
baseURL: tenantConfig.baseURL || tenantConfig.base_url || void 0,
|
|
77
78
|
project: tenantConfig.project,
|
|
78
79
|
location: tenantConfig.location,
|
|
79
80
|
temperature: parseFloat(env.DEFAULT_TEMPERATURE || "0.7"),
|
|
@@ -87,9 +88,11 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
87
88
|
const provider = ((_a = env.LLM_PROVIDER) == null ? void 0 : _a.toLowerCase()) || "openai";
|
|
88
89
|
const providerDefaults = MODEL_CONFIGS[provider] || MODEL_CONFIGS["openai"];
|
|
89
90
|
let apiKey;
|
|
91
|
+
let baseURL;
|
|
90
92
|
let models = { ...providerDefaults };
|
|
91
93
|
if (provider === "openai") {
|
|
92
94
|
apiKey = env.OPENAI_API_KEY;
|
|
95
|
+
baseURL = env.OPENAI_BASE_URL || env.LLM_BASE_URL || void 0;
|
|
93
96
|
models = {
|
|
94
97
|
default: env.OPENAI_MODEL || providerDefaults.default,
|
|
95
98
|
edge: env.OPENAI_MODEL_EDGE || providerDefaults.edge,
|
|
@@ -99,6 +102,7 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
99
102
|
};
|
|
100
103
|
} else if (provider === "gemini") {
|
|
101
104
|
apiKey = env.GEMINI_API_KEY;
|
|
105
|
+
baseURL = env.GEMINI_BASE_URL || env.LLM_BASE_URL || void 0;
|
|
102
106
|
models = {
|
|
103
107
|
default: env.GEMINI_MODEL || providerDefaults.default,
|
|
104
108
|
edge: env.GEMINI_MODEL_EDGE || providerDefaults.edge,
|
|
@@ -108,8 +112,19 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
108
112
|
image: env.GEMINI_IMAGE_MODEL || providerDefaults.image,
|
|
109
113
|
video: env.GEMINI_VIDEO_MODEL || providerDefaults.video
|
|
110
114
|
};
|
|
115
|
+
} else if (provider === "anthropic") {
|
|
116
|
+
apiKey = env.ANTHROPIC_API_KEY;
|
|
117
|
+
baseURL = env.ANTHROPIC_BASE_URL || env.LLM_BASE_URL || void 0;
|
|
118
|
+
models = {
|
|
119
|
+
default: env.ANTHROPIC_MODEL || providerDefaults.default,
|
|
120
|
+
edge: env.ANTHROPIC_MODEL_EDGE || providerDefaults.edge,
|
|
121
|
+
fast: env.ANTHROPIC_MODEL_FAST || providerDefaults.fast,
|
|
122
|
+
cost: env.ANTHROPIC_MODEL_COST || providerDefaults.cost,
|
|
123
|
+
free: env.ANTHROPIC_MODEL_FREE || providerDefaults.free
|
|
124
|
+
};
|
|
111
125
|
} else if (provider === "vertex") {
|
|
112
126
|
apiKey = env.VERTEX_API_KEY;
|
|
127
|
+
baseURL = env.VERTEX_BASE_URL || env.LLM_BASE_URL || void 0;
|
|
113
128
|
const project = env.VERTEX_PROJECT || env.GOOGLE_CLOUD_PROJECT;
|
|
114
129
|
const location = env.VERTEX_LOCATION || env.GOOGLE_CLOUD_LOCATION || "us-central1";
|
|
115
130
|
models = {
|
|
@@ -124,6 +139,7 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
124
139
|
return {
|
|
125
140
|
provider,
|
|
126
141
|
apiKey,
|
|
142
|
+
baseURL,
|
|
127
143
|
project,
|
|
128
144
|
location,
|
|
129
145
|
models,
|
|
@@ -134,6 +150,7 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
134
150
|
return {
|
|
135
151
|
provider,
|
|
136
152
|
apiKey,
|
|
153
|
+
baseURL,
|
|
137
154
|
models,
|
|
138
155
|
temperature: parseFloat(env.DEFAULT_TEMPERATURE || "0.7"),
|
|
139
156
|
maxTokens: parseInt(env.DEFAULT_MAX_TOKENS || "65536")
|
|
@@ -397,7 +414,11 @@ function extractTextAndJson(input) {
|
|
|
397
414
|
var OpenAIProvider = class extends BaseLLMProvider {
|
|
398
415
|
constructor(config) {
|
|
399
416
|
super(config);
|
|
400
|
-
|
|
417
|
+
const clientOptions = { apiKey: config.apiKey };
|
|
418
|
+
if (config.baseURL) {
|
|
419
|
+
clientOptions.baseURL = config.baseURL;
|
|
420
|
+
}
|
|
421
|
+
this.client = new OpenAI(clientOptions);
|
|
401
422
|
this.models = config.models;
|
|
402
423
|
this.defaultModel = config.models.default;
|
|
403
424
|
}
|
|
@@ -579,11 +600,13 @@ var GoogleProvider = class extends BaseLLMProvider {
|
|
|
579
600
|
this.models = config.models;
|
|
580
601
|
this.defaultModel = config.models.default;
|
|
581
602
|
this._pendingOperations = /* @__PURE__ */ new Map();
|
|
603
|
+
const httpOptions = config.baseURL ? { baseUrl: config.baseURL } : void 0;
|
|
582
604
|
if (config.provider === "vertex") {
|
|
583
605
|
if (config.apiKey) {
|
|
584
606
|
this.client = new GoogleGenAI({
|
|
585
607
|
vertexai: true,
|
|
586
|
-
apiKey: config.apiKey
|
|
608
|
+
apiKey: config.apiKey,
|
|
609
|
+
...httpOptions ? { httpOptions } : {}
|
|
587
610
|
});
|
|
588
611
|
} else {
|
|
589
612
|
if (!config.project) {
|
|
@@ -592,12 +615,14 @@ var GoogleProvider = class extends BaseLLMProvider {
|
|
|
592
615
|
this.client = new GoogleGenAI({
|
|
593
616
|
vertexai: true,
|
|
594
617
|
project: config.project,
|
|
595
|
-
location: config.location || "us-central1"
|
|
618
|
+
location: config.location || "us-central1",
|
|
619
|
+
...httpOptions ? { httpOptions } : {}
|
|
596
620
|
});
|
|
597
621
|
}
|
|
598
622
|
} else {
|
|
599
623
|
this.client = new GoogleGenAI({
|
|
600
|
-
apiKey: config.apiKey
|
|
624
|
+
apiKey: config.apiKey,
|
|
625
|
+
...httpOptions ? { httpOptions } : {}
|
|
601
626
|
});
|
|
602
627
|
}
|
|
603
628
|
}
|
|
@@ -726,8 +751,20 @@ ${msg.content}`;
|
|
|
726
751
|
const isLastAssistantMessage = index === geminiMessages.map((m, i) => m.role === "assistant" ? i : -1).filter((i) => i >= 0).pop();
|
|
727
752
|
if (msg.tool_calls) {
|
|
728
753
|
parts2 = msg.tool_calls.map((tc) => {
|
|
754
|
+
let args = tc.function.args;
|
|
755
|
+
if (tc.function.arguments) {
|
|
756
|
+
if (typeof tc.function.arguments === "string") {
|
|
757
|
+
try {
|
|
758
|
+
args = JSON.parse(tc.function.arguments);
|
|
759
|
+
} catch (e) {
|
|
760
|
+
args = {};
|
|
761
|
+
}
|
|
762
|
+
} else {
|
|
763
|
+
args = tc.function.arguments;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
729
766
|
const part = {
|
|
730
|
-
functionCall: { name: tc.function.name, args
|
|
767
|
+
functionCall: { name: tc.function.name, args }
|
|
731
768
|
};
|
|
732
769
|
if (tc.thought_signature) {
|
|
733
770
|
part.thoughtSignature = tc.thought_signature;
|
|
@@ -812,7 +849,10 @@ ${msg.content}`;
|
|
|
812
849
|
thought_signature: responseThoughtSignature,
|
|
813
850
|
tool_calls: toolCalls ? (Array.isArray(toolCalls) ? toolCalls : [toolCalls]).map((fc) => ({
|
|
814
851
|
type: "function",
|
|
815
|
-
function:
|
|
852
|
+
function: {
|
|
853
|
+
name: fc.name,
|
|
854
|
+
arguments: JSON.stringify(fc.args || {})
|
|
855
|
+
},
|
|
816
856
|
thought_signature: fc.thought_signature
|
|
817
857
|
})) : null,
|
|
818
858
|
finishReason: normalizedFinishReason,
|
|
@@ -1134,11 +1174,17 @@ ${prompt}` : prompt;
|
|
|
1134
1174
|
};
|
|
1135
1175
|
|
|
1136
1176
|
// src/llm/providers/anthropic-provider.js
|
|
1177
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
1137
1178
|
var AnthropicProvider = class extends BaseLLMProvider {
|
|
1138
1179
|
constructor(config) {
|
|
1139
1180
|
super(config);
|
|
1140
1181
|
this.models = config.models || {};
|
|
1141
1182
|
this.defaultModel = this.models.default || "claude-3-5-sonnet-20241022";
|
|
1183
|
+
const clientOptions = { apiKey: config.apiKey || "" };
|
|
1184
|
+
if (config.baseURL) {
|
|
1185
|
+
clientOptions.baseURL = config.baseURL;
|
|
1186
|
+
}
|
|
1187
|
+
this.client = new Anthropic(clientOptions);
|
|
1142
1188
|
}
|
|
1143
1189
|
async chat(userMessage, systemPrompt = "", options = {}) {
|
|
1144
1190
|
var _a;
|
|
@@ -1175,82 +1221,69 @@ var AnthropicProvider = class extends BaseLLMProvider {
|
|
|
1175
1221
|
);
|
|
1176
1222
|
}
|
|
1177
1223
|
async _chatCompletionWithModel(messages, systemPrompt, tools, modelName, maxTokens, temperature, options = {}) {
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
const formattedMessages = messages.map((m) => ({
|
|
1181
|
-
role: m.role === "assistant" ? "assistant" : "user",
|
|
1182
|
-
content: m.content
|
|
1183
|
-
}));
|
|
1184
|
-
const headers = {
|
|
1185
|
-
"Content-Type": "application/json",
|
|
1186
|
-
"x-api-key": this.config.apiKey || "",
|
|
1187
|
-
"anthropic-version": "2023-06-01"
|
|
1188
|
-
};
|
|
1189
|
-
const payload = {
|
|
1190
|
-
model: modelName,
|
|
1191
|
-
messages: formattedMessages,
|
|
1192
|
-
max_tokens: maxTokens,
|
|
1193
|
-
temperature
|
|
1194
|
-
};
|
|
1195
|
-
if (systemPrompt) {
|
|
1196
|
-
payload.system = systemPrompt;
|
|
1197
|
-
}
|
|
1224
|
+
var _a, _b, _c, _d;
|
|
1225
|
+
let effectiveSystem = systemPrompt || void 0;
|
|
1198
1226
|
if (options.responseFormat) {
|
|
1199
1227
|
const formatType = typeof options.responseFormat === "string" ? options.responseFormat : options.responseFormat.type;
|
|
1200
1228
|
if (formatType === "json" || formatType === "json_schema") {
|
|
1201
|
-
const
|
|
1229
|
+
const schema = options.responseFormat.schema || options.responseSchema;
|
|
1230
|
+
const schemaText = schema ? `
|
|
1202
1231
|
|
|
1203
|
-
Your output must comply strictly with this JSON Schema: ${JSON.stringify(
|
|
1232
|
+
Your output must comply strictly with this JSON Schema: ${JSON.stringify(schema)}` : "";
|
|
1204
1233
|
const jsonPrompt = `IMPORTANT: You must respond ONLY in raw JSON format. Do not write any conversational text, explanations, or markdown code blocks (e.g. do NOT wrap your answer in \`\`\`json ... \`\`\`). Your response must start with '{' and end with '}'.${schemaText}`;
|
|
1205
|
-
|
|
1206
|
-
payload.system = `${payload.system}
|
|
1234
|
+
effectiveSystem = effectiveSystem ? `${effectiveSystem}
|
|
1207
1235
|
|
|
1208
|
-
${jsonPrompt}
|
|
1209
|
-
} else {
|
|
1210
|
-
payload.system = jsonPrompt;
|
|
1211
|
-
}
|
|
1236
|
+
${jsonPrompt}` : jsonPrompt;
|
|
1212
1237
|
}
|
|
1213
1238
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1239
|
+
const anthropicMessages = this._formatMessages(messages);
|
|
1240
|
+
const anthropicTools = tools ? this._formatTools(tools) : void 0;
|
|
1241
|
+
const requestParams = {
|
|
1242
|
+
model: modelName,
|
|
1243
|
+
max_tokens: maxTokens,
|
|
1244
|
+
temperature,
|
|
1245
|
+
messages: anthropicMessages,
|
|
1246
|
+
...effectiveSystem ? { system: effectiveSystem } : {},
|
|
1247
|
+
...anthropicTools ? { tools: anthropicTools } : {}
|
|
1248
|
+
};
|
|
1249
|
+
let response;
|
|
1216
1250
|
try {
|
|
1217
|
-
|
|
1218
|
-
method: "POST",
|
|
1219
|
-
headers,
|
|
1220
|
-
body: JSON.stringify(payload)
|
|
1221
|
-
});
|
|
1222
|
-
responseText = await res.text();
|
|
1223
|
-
if (!res.ok) {
|
|
1224
|
-
console.error(`[AnthropicProvider] API request failed with status ${res.status}:`, responseText);
|
|
1225
|
-
throw new LLMServiceException(`Anthropic API Error: ${responseText}`, res.status);
|
|
1226
|
-
}
|
|
1227
|
-
responseData = JSON.parse(responseText);
|
|
1251
|
+
response = await this.client.messages.create(requestParams);
|
|
1228
1252
|
} catch (error) {
|
|
1229
1253
|
console.error(`[AnthropicProvider] request failed (API Key: ${this._getMaskedApiKey()}):`, error);
|
|
1230
1254
|
throw error;
|
|
1231
1255
|
}
|
|
1232
|
-
const
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1256
|
+
const textBlocks = response.content.filter((b) => b.type === "text");
|
|
1257
|
+
const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");
|
|
1258
|
+
const contentText = textBlocks.map((b) => b.text).join("");
|
|
1259
|
+
if (!contentText && toolUseBlocks.length === 0) {
|
|
1260
|
+
console.error("[AnthropicProvider] Model returned empty response (no text, no tool calls)");
|
|
1236
1261
|
throw new LLMServiceException(
|
|
1237
1262
|
"Model returned empty response. This usually means the prompt or schema is confusing the model.",
|
|
1238
1263
|
500
|
|
1239
1264
|
);
|
|
1240
1265
|
}
|
|
1241
|
-
const
|
|
1266
|
+
const toolCalls = toolUseBlocks.length > 0 ? toolUseBlocks.map((block) => ({
|
|
1267
|
+
id: block.id,
|
|
1268
|
+
type: "function",
|
|
1269
|
+
function: {
|
|
1270
|
+
name: block.name,
|
|
1271
|
+
// Anthropic returns args as a parsed object; serialize to string to match OpenAI shape
|
|
1272
|
+
arguments: JSON.stringify(block.input || {})
|
|
1273
|
+
}
|
|
1274
|
+
})) : null;
|
|
1275
|
+
const rawFinishReason = response.stop_reason;
|
|
1242
1276
|
const normalizedFinishReason = this.normalizeFinishReason(rawFinishReason);
|
|
1243
1277
|
const result = {
|
|
1244
1278
|
content: contentText,
|
|
1245
|
-
tool_calls:
|
|
1246
|
-
// REST client tool calls mapping not required for playbook studio
|
|
1279
|
+
tool_calls: toolCalls,
|
|
1247
1280
|
finishReason: normalizedFinishReason,
|
|
1248
1281
|
_rawFinishReason: rawFinishReason,
|
|
1249
1282
|
_responseFormat: options.responseFormat,
|
|
1250
1283
|
usage: {
|
|
1251
|
-
prompt_tokens:
|
|
1252
|
-
completion_tokens:
|
|
1253
|
-
total_tokens:
|
|
1284
|
+
prompt_tokens: ((_a = response.usage) == null ? void 0 : _a.input_tokens) || 0,
|
|
1285
|
+
completion_tokens: ((_b = response.usage) == null ? void 0 : _b.output_tokens) || 0,
|
|
1286
|
+
total_tokens: (((_c = response.usage) == null ? void 0 : _c.input_tokens) || 0) + (((_d = response.usage) == null ? void 0 : _d.output_tokens) || 0)
|
|
1254
1287
|
},
|
|
1255
1288
|
model: modelName
|
|
1256
1289
|
};
|
|
@@ -1259,11 +1292,110 @@ ${jsonPrompt}`;
|
|
|
1259
1292
|
}
|
|
1260
1293
|
return result;
|
|
1261
1294
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1295
|
+
/**
|
|
1296
|
+
* Convert standard {role, content, tool_calls, tool_call_id} messages
|
|
1297
|
+
* to Anthropic's message format.
|
|
1298
|
+
*
|
|
1299
|
+
* Key differences from OpenAI:
|
|
1300
|
+
* - No 'system' role in messages array (handled via top-level `system` param)
|
|
1301
|
+
* - Tool results go as role:'user' with content type:'tool_result'
|
|
1302
|
+
* - Assistant messages with tool calls use an array of content blocks
|
|
1303
|
+
* - Roles must strictly alternate user/assistant
|
|
1304
|
+
*/
|
|
1305
|
+
_formatMessages(messages) {
|
|
1306
|
+
const result = [];
|
|
1307
|
+
for (const msg of messages) {
|
|
1308
|
+
if (msg.role === "system") {
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
if (msg.role === "tool") {
|
|
1312
|
+
const toolResultBlock = {
|
|
1313
|
+
type: "tool_result",
|
|
1314
|
+
tool_use_id: msg.tool_call_id,
|
|
1315
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
1316
|
+
};
|
|
1317
|
+
const last = result[result.length - 1];
|
|
1318
|
+
if (last && last.role === "user" && Array.isArray(last.content)) {
|
|
1319
|
+
last.content.push(toolResultBlock);
|
|
1320
|
+
} else {
|
|
1321
|
+
result.push({ role: "user", content: [toolResultBlock] });
|
|
1322
|
+
}
|
|
1323
|
+
continue;
|
|
1324
|
+
}
|
|
1325
|
+
if (msg.role === "assistant") {
|
|
1326
|
+
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
|
1327
|
+
const contentBlocks = [];
|
|
1328
|
+
if (msg.content) {
|
|
1329
|
+
contentBlocks.push({ type: "text", text: msg.content });
|
|
1330
|
+
}
|
|
1331
|
+
for (const tc of msg.tool_calls) {
|
|
1332
|
+
let inputArgs = tc.function.arguments;
|
|
1333
|
+
if (typeof inputArgs === "string") {
|
|
1334
|
+
try {
|
|
1335
|
+
inputArgs = JSON.parse(inputArgs);
|
|
1336
|
+
} catch (_) {
|
|
1337
|
+
inputArgs = {};
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
contentBlocks.push({
|
|
1341
|
+
type: "tool_use",
|
|
1342
|
+
id: tc.id,
|
|
1343
|
+
name: tc.function.name,
|
|
1344
|
+
input: inputArgs
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
result.push({ role: "assistant", content: contentBlocks });
|
|
1348
|
+
} else {
|
|
1349
|
+
result.push({ role: "assistant", content: msg.content || "" });
|
|
1350
|
+
}
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
result.push({ role: "user", content: msg.content || "" });
|
|
1265
1354
|
}
|
|
1266
|
-
return
|
|
1355
|
+
return result;
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Convert OpenAI-style tool definitions to Anthropic format.
|
|
1359
|
+
* OpenAI: { type: 'function', function: { name, description, parameters } }
|
|
1360
|
+
* Anthropic: { name, description, input_schema }
|
|
1361
|
+
*/
|
|
1362
|
+
_formatTools(tools) {
|
|
1363
|
+
return tools.map((tool) => {
|
|
1364
|
+
const fn = tool.function || tool;
|
|
1365
|
+
return {
|
|
1366
|
+
name: fn.name,
|
|
1367
|
+
description: fn.description || "",
|
|
1368
|
+
input_schema: fn.parameters || fn.input_schema || { type: "object", properties: {} }
|
|
1369
|
+
};
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
async executeTools(tool_calls, messages, tenantId, toolImplementations, env) {
|
|
1373
|
+
const toolResults = await Promise.all(
|
|
1374
|
+
tool_calls.map(async (toolCall) => {
|
|
1375
|
+
const toolName = toolCall.function.name;
|
|
1376
|
+
const tool = toolImplementations[toolName];
|
|
1377
|
+
console.log(`[Tool Call] ${toolName} with arguments:`, toolCall.function.arguments);
|
|
1378
|
+
if (!tool) {
|
|
1379
|
+
console.error(`[Tool Error] Tool '${toolName}' not found`);
|
|
1380
|
+
return { tool_call_id: toolCall.id, output: JSON.stringify({ error: `Tool '${toolName}' not found.` }) };
|
|
1381
|
+
}
|
|
1382
|
+
try {
|
|
1383
|
+
const output = await tool(toolCall.function.arguments, { env, tenantId });
|
|
1384
|
+
const preview = typeof output === "string" ? output.length > 200 ? output.substring(0, 200) + "..." : output : JSON.stringify(output).substring(0, 200) + "...";
|
|
1385
|
+
console.log(`[Tool Result] ${toolName} returned:`, preview);
|
|
1386
|
+
return { tool_call_id: toolCall.id, output };
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
console.error(`[Tool Error] ${toolName} failed:`, error.message);
|
|
1389
|
+
return { tool_call_id: toolCall.id, output: JSON.stringify({ error: `Error executing tool '${toolName}': ${error.message}` }) };
|
|
1390
|
+
}
|
|
1391
|
+
})
|
|
1392
|
+
);
|
|
1393
|
+
toolResults.forEach(
|
|
1394
|
+
(result) => messages.push({ role: "tool", tool_call_id: result.tool_call_id, content: result.output })
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
_getModelForTier(tier) {
|
|
1398
|
+
return this.models[tier] || this.defaultModel;
|
|
1267
1399
|
}
|
|
1268
1400
|
_shouldAutoParse(options) {
|
|
1269
1401
|
if (!options.responseFormat) return false;
|
|
@@ -1284,15 +1416,10 @@ ${jsonPrompt}`;
|
|
|
1284
1416
|
}
|
|
1285
1417
|
normalizeFinishReason(providerReason) {
|
|
1286
1418
|
const lower = (providerReason || "").toLowerCase();
|
|
1287
|
-
if (lower === "end_turn")
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (lower === "
|
|
1291
|
-
return "truncated";
|
|
1292
|
-
}
|
|
1293
|
-
if (lower === "stop_sequence") {
|
|
1294
|
-
return "completed";
|
|
1295
|
-
}
|
|
1419
|
+
if (lower === "end_turn") return "completed";
|
|
1420
|
+
if (lower === "max_tokens") return "truncated";
|
|
1421
|
+
if (lower === "stop_sequence") return "completed";
|
|
1422
|
+
if (lower === "tool_use") return "tool_call";
|
|
1296
1423
|
return super.normalizeFinishReason(providerReason);
|
|
1297
1424
|
}
|
|
1298
1425
|
};
|