@contentgrowth/llm-service 1.2.2 → 1.2.3
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/index.cjs +192 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -1
- package/dist/index.d.ts +51 -1
- package/dist/index.js +191 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
31
31
|
// src/index.js
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
|
+
AnthropicProvider: () => AnthropicProvider,
|
|
34
35
|
BaseConfigProvider: () => BaseConfigProvider,
|
|
35
36
|
ConfigManager: () => ConfigManager,
|
|
36
37
|
DefaultConfigProvider: () => DefaultConfigProvider,
|
|
@@ -194,35 +195,36 @@ var DefaultConfigProvider = class extends BaseConfigProvider {
|
|
|
194
195
|
// src/llm/config-manager.js
|
|
195
196
|
var MODEL_CONFIGS = {
|
|
196
197
|
openai: {
|
|
197
|
-
default: "gpt-
|
|
198
|
-
edge: "gpt-
|
|
199
|
-
fast: "gpt-
|
|
200
|
-
cost: "gpt-
|
|
201
|
-
free: "gpt-
|
|
198
|
+
default: "gpt-5.5-instant",
|
|
199
|
+
edge: "gpt-5.5-thinking",
|
|
200
|
+
fast: "gpt-5.5-instant",
|
|
201
|
+
cost: "gpt-5.5-instant",
|
|
202
|
+
free: "gpt-5.5-instant"
|
|
202
203
|
},
|
|
203
204
|
gemini: {
|
|
204
|
-
default: "gemini-3-flash
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// 'gemini-2.5-flash-lite',
|
|
210
|
-
cost: "gemini-3-flash-preview",
|
|
211
|
-
// 'gemini-2.5-flash-lite',
|
|
212
|
-
free: "gemini-3-flash-preview",
|
|
213
|
-
// 'gemini-2.0-flash-lite',
|
|
205
|
+
default: "gemini-3.5-flash",
|
|
206
|
+
edge: "gemini-3.5-pro",
|
|
207
|
+
fast: "gemini-3.5-flash",
|
|
208
|
+
cost: "gemini-3.5-flash",
|
|
209
|
+
free: "gemini-3.5-flash",
|
|
214
210
|
video: "veo",
|
|
215
|
-
image: "gemini-3-pro-image-preview"
|
|
216
|
-
// Default image generation model
|
|
211
|
+
image: "gemini-3.5-pro-image-preview"
|
|
217
212
|
},
|
|
218
213
|
vertex: {
|
|
219
|
-
default: "gemini-3-flash
|
|
220
|
-
edge: "gemini-3-pro
|
|
221
|
-
fast: "gemini-3-flash
|
|
222
|
-
cost: "gemini-3-flash
|
|
223
|
-
free: "gemini-3-flash
|
|
214
|
+
default: "gemini-3.5-flash",
|
|
215
|
+
edge: "gemini-3.5-pro",
|
|
216
|
+
fast: "gemini-3.5-flash",
|
|
217
|
+
cost: "gemini-3.5-flash",
|
|
218
|
+
free: "gemini-3.5-flash",
|
|
224
219
|
video: "veo",
|
|
225
|
-
image: "gemini-3-pro-image-preview"
|
|
220
|
+
image: "gemini-3.5-pro-image-preview"
|
|
221
|
+
},
|
|
222
|
+
anthropic: {
|
|
223
|
+
default: "claude-4.6-sonnet",
|
|
224
|
+
edge: "claude-4.8-opus",
|
|
225
|
+
fast: "claude-4.5-haiku",
|
|
226
|
+
cost: "claude-4.5-haiku",
|
|
227
|
+
free: "claude-4.5-haiku"
|
|
226
228
|
}
|
|
227
229
|
};
|
|
228
230
|
var ConfigManager = class {
|
|
@@ -1182,6 +1184,170 @@ ${prompt}` : prompt;
|
|
|
1182
1184
|
}
|
|
1183
1185
|
};
|
|
1184
1186
|
|
|
1187
|
+
// src/llm/providers/anthropic-provider.js
|
|
1188
|
+
var AnthropicProvider = class extends BaseLLMProvider {
|
|
1189
|
+
constructor(config) {
|
|
1190
|
+
super(config);
|
|
1191
|
+
this.models = config.models || {};
|
|
1192
|
+
this.defaultModel = this.models.default || "claude-3-5-sonnet-20241022";
|
|
1193
|
+
}
|
|
1194
|
+
async chat(userMessage, systemPrompt = "", options = {}) {
|
|
1195
|
+
var _a;
|
|
1196
|
+
const messages = [{ role: "user", content: userMessage }];
|
|
1197
|
+
const tier = options.tier || "default";
|
|
1198
|
+
const effectiveModel = this._getModelForTier(tier);
|
|
1199
|
+
const effectiveMaxTokens = options.maxTokens || this.config.maxTokens || 4096;
|
|
1200
|
+
const effectiveTemperature = options.temperature !== void 0 ? options.temperature : (_a = this.config.temperature) != null ? _a : 0.7;
|
|
1201
|
+
const response = await this._chatCompletionWithModel(
|
|
1202
|
+
messages,
|
|
1203
|
+
systemPrompt,
|
|
1204
|
+
null,
|
|
1205
|
+
effectiveModel,
|
|
1206
|
+
effectiveMaxTokens,
|
|
1207
|
+
effectiveTemperature,
|
|
1208
|
+
options
|
|
1209
|
+
);
|
|
1210
|
+
return { text: response.content };
|
|
1211
|
+
}
|
|
1212
|
+
async chatCompletion(messages, systemPrompt, tools = null, options = {}) {
|
|
1213
|
+
var _a;
|
|
1214
|
+
const tier = options.tier || "default";
|
|
1215
|
+
const effectiveModel = this._getModelForTier(tier);
|
|
1216
|
+
const effectiveMaxTokens = options.maxTokens || this.config.maxTokens || 4096;
|
|
1217
|
+
const effectiveTemperature = options.temperature !== void 0 ? options.temperature : (_a = this.config.temperature) != null ? _a : 0.7;
|
|
1218
|
+
return this._chatCompletionWithModel(
|
|
1219
|
+
messages,
|
|
1220
|
+
systemPrompt,
|
|
1221
|
+
tools,
|
|
1222
|
+
effectiveModel,
|
|
1223
|
+
effectiveMaxTokens,
|
|
1224
|
+
effectiveTemperature,
|
|
1225
|
+
options
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
async _chatCompletionWithModel(messages, systemPrompt, tools, modelName, maxTokens, temperature, options = {}) {
|
|
1229
|
+
const baseURL = this.config.baseURL || "https://api.anthropic.com";
|
|
1230
|
+
const url = `${baseURL.replace(/\/$/, "")}/v1/messages`;
|
|
1231
|
+
const formattedMessages = messages.map((m) => ({
|
|
1232
|
+
role: m.role === "assistant" ? "assistant" : "user",
|
|
1233
|
+
content: m.content
|
|
1234
|
+
}));
|
|
1235
|
+
const headers = {
|
|
1236
|
+
"Content-Type": "application/json",
|
|
1237
|
+
"x-api-key": this.config.apiKey || "",
|
|
1238
|
+
"anthropic-version": "2023-06-01"
|
|
1239
|
+
};
|
|
1240
|
+
const payload = {
|
|
1241
|
+
model: modelName,
|
|
1242
|
+
messages: formattedMessages,
|
|
1243
|
+
max_tokens: maxTokens,
|
|
1244
|
+
temperature
|
|
1245
|
+
};
|
|
1246
|
+
if (systemPrompt) {
|
|
1247
|
+
payload.system = systemPrompt;
|
|
1248
|
+
}
|
|
1249
|
+
if (options.responseFormat) {
|
|
1250
|
+
const formatType = typeof options.responseFormat === "string" ? options.responseFormat : options.responseFormat.type;
|
|
1251
|
+
if (formatType === "json" || formatType === "json_schema") {
|
|
1252
|
+
const schemaText = options.responseFormat.schema || options.responseSchema ? `
|
|
1253
|
+
|
|
1254
|
+
Your output must comply strictly with this JSON Schema: ${JSON.stringify(options.responseFormat.schema || options.responseSchema)}` : "";
|
|
1255
|
+
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}`;
|
|
1256
|
+
if (payload.system) {
|
|
1257
|
+
payload.system = `${payload.system}
|
|
1258
|
+
|
|
1259
|
+
${jsonPrompt}`;
|
|
1260
|
+
} else {
|
|
1261
|
+
payload.system = jsonPrompt;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
let responseText;
|
|
1266
|
+
let responseData;
|
|
1267
|
+
try {
|
|
1268
|
+
const res = await fetch(url, {
|
|
1269
|
+
method: "POST",
|
|
1270
|
+
headers,
|
|
1271
|
+
body: JSON.stringify(payload)
|
|
1272
|
+
});
|
|
1273
|
+
responseText = await res.text();
|
|
1274
|
+
if (!res.ok) {
|
|
1275
|
+
console.error(`[AnthropicProvider] API request failed with status ${res.status}:`, responseText);
|
|
1276
|
+
throw new LLMServiceException(`Anthropic API Error: ${responseText}`, res.status);
|
|
1277
|
+
}
|
|
1278
|
+
responseData = JSON.parse(responseText);
|
|
1279
|
+
} catch (error) {
|
|
1280
|
+
console.error(`[AnthropicProvider] request failed (API Key: ${this._getMaskedApiKey()}):`, error);
|
|
1281
|
+
throw error;
|
|
1282
|
+
}
|
|
1283
|
+
const contentBlock = responseData.content && responseData.content[0];
|
|
1284
|
+
const contentText = contentBlock ? contentBlock.text : "";
|
|
1285
|
+
if (!contentText) {
|
|
1286
|
+
console.error("[AnthropicProvider] Model returned empty response content");
|
|
1287
|
+
throw new LLMServiceException(
|
|
1288
|
+
"Model returned empty response. This usually means the prompt or schema is confusing the model.",
|
|
1289
|
+
500
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
const rawFinishReason = responseData.stop_reason;
|
|
1293
|
+
const normalizedFinishReason = this.normalizeFinishReason(rawFinishReason);
|
|
1294
|
+
const result = {
|
|
1295
|
+
content: contentText,
|
|
1296
|
+
tool_calls: null,
|
|
1297
|
+
// REST client tool calls mapping not required for playbook studio
|
|
1298
|
+
finishReason: normalizedFinishReason,
|
|
1299
|
+
_rawFinishReason: rawFinishReason,
|
|
1300
|
+
_responseFormat: options.responseFormat,
|
|
1301
|
+
usage: {
|
|
1302
|
+
prompt_tokens: responseData.usage ? responseData.usage.input_tokens : 0,
|
|
1303
|
+
completion_tokens: responseData.usage ? responseData.usage.output_tokens : 0,
|
|
1304
|
+
total_tokens: responseData.usage ? responseData.usage.input_tokens + responseData.usage.output_tokens : 0
|
|
1305
|
+
},
|
|
1306
|
+
model: modelName
|
|
1307
|
+
};
|
|
1308
|
+
if (options.responseFormat && this._shouldAutoParse(options)) {
|
|
1309
|
+
result.parsedContent = this._safeJsonParse(contentText);
|
|
1310
|
+
}
|
|
1311
|
+
return result;
|
|
1312
|
+
}
|
|
1313
|
+
_getModelForTier(tier) {
|
|
1314
|
+
if (this.models[tier]) {
|
|
1315
|
+
return this.models[tier];
|
|
1316
|
+
}
|
|
1317
|
+
return this.defaultModel;
|
|
1318
|
+
}
|
|
1319
|
+
_shouldAutoParse(options) {
|
|
1320
|
+
if (!options.responseFormat) return false;
|
|
1321
|
+
const formatType = typeof options.responseFormat === "string" ? options.responseFormat : options.responseFormat.type;
|
|
1322
|
+
return formatType === "json" || formatType === "json_schema";
|
|
1323
|
+
}
|
|
1324
|
+
_safeJsonParse(text) {
|
|
1325
|
+
try {
|
|
1326
|
+
return extractJsonFromResponse(text);
|
|
1327
|
+
} catch (error) {
|
|
1328
|
+
console.error("[AnthropicProvider] Failed to extract JSON from response:", text, error);
|
|
1329
|
+
try {
|
|
1330
|
+
return JSON.parse(text);
|
|
1331
|
+
} catch (_) {
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
normalizeFinishReason(providerReason) {
|
|
1337
|
+
const lower = (providerReason || "").toLowerCase();
|
|
1338
|
+
if (lower === "end_turn") {
|
|
1339
|
+
return "completed";
|
|
1340
|
+
}
|
|
1341
|
+
if (lower === "max_tokens") {
|
|
1342
|
+
return "truncated";
|
|
1343
|
+
}
|
|
1344
|
+
if (lower === "stop_sequence") {
|
|
1345
|
+
return "completed";
|
|
1346
|
+
}
|
|
1347
|
+
return super.normalizeFinishReason(providerReason);
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
|
|
1185
1351
|
// src/llm-service.js
|
|
1186
1352
|
var LLMService = class {
|
|
1187
1353
|
constructor(env, toolImplementations = {}) {
|
|
@@ -1203,6 +1369,8 @@ var LLMService = class {
|
|
|
1203
1369
|
provider = new OpenAIProvider(config);
|
|
1204
1370
|
} else if (config.provider === "gemini" || config.provider === "vertex") {
|
|
1205
1371
|
provider = new GoogleProvider(config);
|
|
1372
|
+
} else if (config.provider === "anthropic") {
|
|
1373
|
+
provider = new AnthropicProvider(config);
|
|
1206
1374
|
} else {
|
|
1207
1375
|
throw new LLMServiceException(`Unsupported LLM provider: ${config.provider}`, 500);
|
|
1208
1376
|
}
|
|
@@ -1771,6 +1939,7 @@ function createSpeechHandler(app, getConfig) {
|
|
|
1771
1939
|
}
|
|
1772
1940
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1773
1941
|
0 && (module.exports = {
|
|
1942
|
+
AnthropicProvider,
|
|
1774
1943
|
BaseConfigProvider,
|
|
1775
1944
|
ConfigManager,
|
|
1776
1945
|
DefaultConfigProvider,
|