@contentgrowth/llm-service 1.2.2 → 1.2.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/dist/index.cjs +209 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -3
- package/dist/index.d.ts +59 -3
- package/dist/index.js +208 -25
- 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 {
|
|
@@ -775,8 +777,20 @@ ${msg.content}`;
|
|
|
775
777
|
const isLastAssistantMessage = index === geminiMessages.map((m, i) => m.role === "assistant" ? i : -1).filter((i) => i >= 0).pop();
|
|
776
778
|
if (msg.tool_calls) {
|
|
777
779
|
parts2 = msg.tool_calls.map((tc) => {
|
|
780
|
+
let args = tc.function.args;
|
|
781
|
+
if (tc.function.arguments) {
|
|
782
|
+
if (typeof tc.function.arguments === "string") {
|
|
783
|
+
try {
|
|
784
|
+
args = JSON.parse(tc.function.arguments);
|
|
785
|
+
} catch (e) {
|
|
786
|
+
args = {};
|
|
787
|
+
}
|
|
788
|
+
} else {
|
|
789
|
+
args = tc.function.arguments;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
778
792
|
const part = {
|
|
779
|
-
functionCall: { name: tc.function.name, args
|
|
793
|
+
functionCall: { name: tc.function.name, args }
|
|
780
794
|
};
|
|
781
795
|
if (tc.thought_signature) {
|
|
782
796
|
part.thoughtSignature = tc.thought_signature;
|
|
@@ -861,7 +875,10 @@ ${msg.content}`;
|
|
|
861
875
|
thought_signature: responseThoughtSignature,
|
|
862
876
|
tool_calls: toolCalls ? (Array.isArray(toolCalls) ? toolCalls : [toolCalls]).map((fc) => ({
|
|
863
877
|
type: "function",
|
|
864
|
-
function:
|
|
878
|
+
function: {
|
|
879
|
+
name: fc.name,
|
|
880
|
+
arguments: JSON.stringify(fc.args || {})
|
|
881
|
+
},
|
|
865
882
|
thought_signature: fc.thought_signature
|
|
866
883
|
})) : null,
|
|
867
884
|
finishReason: normalizedFinishReason,
|
|
@@ -1182,6 +1199,170 @@ ${prompt}` : prompt;
|
|
|
1182
1199
|
}
|
|
1183
1200
|
};
|
|
1184
1201
|
|
|
1202
|
+
// src/llm/providers/anthropic-provider.js
|
|
1203
|
+
var AnthropicProvider = class extends BaseLLMProvider {
|
|
1204
|
+
constructor(config) {
|
|
1205
|
+
super(config);
|
|
1206
|
+
this.models = config.models || {};
|
|
1207
|
+
this.defaultModel = this.models.default || "claude-3-5-sonnet-20241022";
|
|
1208
|
+
}
|
|
1209
|
+
async chat(userMessage, systemPrompt = "", options = {}) {
|
|
1210
|
+
var _a;
|
|
1211
|
+
const messages = [{ role: "user", content: userMessage }];
|
|
1212
|
+
const tier = options.tier || "default";
|
|
1213
|
+
const effectiveModel = this._getModelForTier(tier);
|
|
1214
|
+
const effectiveMaxTokens = options.maxTokens || this.config.maxTokens || 4096;
|
|
1215
|
+
const effectiveTemperature = options.temperature !== void 0 ? options.temperature : (_a = this.config.temperature) != null ? _a : 0.7;
|
|
1216
|
+
const response = await this._chatCompletionWithModel(
|
|
1217
|
+
messages,
|
|
1218
|
+
systemPrompt,
|
|
1219
|
+
null,
|
|
1220
|
+
effectiveModel,
|
|
1221
|
+
effectiveMaxTokens,
|
|
1222
|
+
effectiveTemperature,
|
|
1223
|
+
options
|
|
1224
|
+
);
|
|
1225
|
+
return { text: response.content };
|
|
1226
|
+
}
|
|
1227
|
+
async chatCompletion(messages, systemPrompt, tools = null, options = {}) {
|
|
1228
|
+
var _a;
|
|
1229
|
+
const tier = options.tier || "default";
|
|
1230
|
+
const effectiveModel = this._getModelForTier(tier);
|
|
1231
|
+
const effectiveMaxTokens = options.maxTokens || this.config.maxTokens || 4096;
|
|
1232
|
+
const effectiveTemperature = options.temperature !== void 0 ? options.temperature : (_a = this.config.temperature) != null ? _a : 0.7;
|
|
1233
|
+
return this._chatCompletionWithModel(
|
|
1234
|
+
messages,
|
|
1235
|
+
systemPrompt,
|
|
1236
|
+
tools,
|
|
1237
|
+
effectiveModel,
|
|
1238
|
+
effectiveMaxTokens,
|
|
1239
|
+
effectiveTemperature,
|
|
1240
|
+
options
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
async _chatCompletionWithModel(messages, systemPrompt, tools, modelName, maxTokens, temperature, options = {}) {
|
|
1244
|
+
const baseURL = this.config.baseURL || "https://api.anthropic.com";
|
|
1245
|
+
const url = `${baseURL.replace(/\/$/, "")}/v1/messages`;
|
|
1246
|
+
const formattedMessages = messages.map((m) => ({
|
|
1247
|
+
role: m.role === "assistant" ? "assistant" : "user",
|
|
1248
|
+
content: m.content
|
|
1249
|
+
}));
|
|
1250
|
+
const headers = {
|
|
1251
|
+
"Content-Type": "application/json",
|
|
1252
|
+
"x-api-key": this.config.apiKey || "",
|
|
1253
|
+
"anthropic-version": "2023-06-01"
|
|
1254
|
+
};
|
|
1255
|
+
const payload = {
|
|
1256
|
+
model: modelName,
|
|
1257
|
+
messages: formattedMessages,
|
|
1258
|
+
max_tokens: maxTokens,
|
|
1259
|
+
temperature
|
|
1260
|
+
};
|
|
1261
|
+
if (systemPrompt) {
|
|
1262
|
+
payload.system = systemPrompt;
|
|
1263
|
+
}
|
|
1264
|
+
if (options.responseFormat) {
|
|
1265
|
+
const formatType = typeof options.responseFormat === "string" ? options.responseFormat : options.responseFormat.type;
|
|
1266
|
+
if (formatType === "json" || formatType === "json_schema") {
|
|
1267
|
+
const schemaText = options.responseFormat.schema || options.responseSchema ? `
|
|
1268
|
+
|
|
1269
|
+
Your output must comply strictly with this JSON Schema: ${JSON.stringify(options.responseFormat.schema || options.responseSchema)}` : "";
|
|
1270
|
+
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}`;
|
|
1271
|
+
if (payload.system) {
|
|
1272
|
+
payload.system = `${payload.system}
|
|
1273
|
+
|
|
1274
|
+
${jsonPrompt}`;
|
|
1275
|
+
} else {
|
|
1276
|
+
payload.system = jsonPrompt;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
let responseText;
|
|
1281
|
+
let responseData;
|
|
1282
|
+
try {
|
|
1283
|
+
const res = await fetch(url, {
|
|
1284
|
+
method: "POST",
|
|
1285
|
+
headers,
|
|
1286
|
+
body: JSON.stringify(payload)
|
|
1287
|
+
});
|
|
1288
|
+
responseText = await res.text();
|
|
1289
|
+
if (!res.ok) {
|
|
1290
|
+
console.error(`[AnthropicProvider] API request failed with status ${res.status}:`, responseText);
|
|
1291
|
+
throw new LLMServiceException(`Anthropic API Error: ${responseText}`, res.status);
|
|
1292
|
+
}
|
|
1293
|
+
responseData = JSON.parse(responseText);
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
console.error(`[AnthropicProvider] request failed (API Key: ${this._getMaskedApiKey()}):`, error);
|
|
1296
|
+
throw error;
|
|
1297
|
+
}
|
|
1298
|
+
const contentBlock = responseData.content && responseData.content[0];
|
|
1299
|
+
const contentText = contentBlock ? contentBlock.text : "";
|
|
1300
|
+
if (!contentText) {
|
|
1301
|
+
console.error("[AnthropicProvider] Model returned empty response content");
|
|
1302
|
+
throw new LLMServiceException(
|
|
1303
|
+
"Model returned empty response. This usually means the prompt or schema is confusing the model.",
|
|
1304
|
+
500
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
const rawFinishReason = responseData.stop_reason;
|
|
1308
|
+
const normalizedFinishReason = this.normalizeFinishReason(rawFinishReason);
|
|
1309
|
+
const result = {
|
|
1310
|
+
content: contentText,
|
|
1311
|
+
tool_calls: null,
|
|
1312
|
+
// REST client tool calls mapping not required for playbook studio
|
|
1313
|
+
finishReason: normalizedFinishReason,
|
|
1314
|
+
_rawFinishReason: rawFinishReason,
|
|
1315
|
+
_responseFormat: options.responseFormat,
|
|
1316
|
+
usage: {
|
|
1317
|
+
prompt_tokens: responseData.usage ? responseData.usage.input_tokens : 0,
|
|
1318
|
+
completion_tokens: responseData.usage ? responseData.usage.output_tokens : 0,
|
|
1319
|
+
total_tokens: responseData.usage ? responseData.usage.input_tokens + responseData.usage.output_tokens : 0
|
|
1320
|
+
},
|
|
1321
|
+
model: modelName
|
|
1322
|
+
};
|
|
1323
|
+
if (options.responseFormat && this._shouldAutoParse(options)) {
|
|
1324
|
+
result.parsedContent = this._safeJsonParse(contentText);
|
|
1325
|
+
}
|
|
1326
|
+
return result;
|
|
1327
|
+
}
|
|
1328
|
+
_getModelForTier(tier) {
|
|
1329
|
+
if (this.models[tier]) {
|
|
1330
|
+
return this.models[tier];
|
|
1331
|
+
}
|
|
1332
|
+
return this.defaultModel;
|
|
1333
|
+
}
|
|
1334
|
+
_shouldAutoParse(options) {
|
|
1335
|
+
if (!options.responseFormat) return false;
|
|
1336
|
+
const formatType = typeof options.responseFormat === "string" ? options.responseFormat : options.responseFormat.type;
|
|
1337
|
+
return formatType === "json" || formatType === "json_schema";
|
|
1338
|
+
}
|
|
1339
|
+
_safeJsonParse(text) {
|
|
1340
|
+
try {
|
|
1341
|
+
return extractJsonFromResponse(text);
|
|
1342
|
+
} catch (error) {
|
|
1343
|
+
console.error("[AnthropicProvider] Failed to extract JSON from response:", text, error);
|
|
1344
|
+
try {
|
|
1345
|
+
return JSON.parse(text);
|
|
1346
|
+
} catch (_) {
|
|
1347
|
+
return null;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
normalizeFinishReason(providerReason) {
|
|
1352
|
+
const lower = (providerReason || "").toLowerCase();
|
|
1353
|
+
if (lower === "end_turn") {
|
|
1354
|
+
return "completed";
|
|
1355
|
+
}
|
|
1356
|
+
if (lower === "max_tokens") {
|
|
1357
|
+
return "truncated";
|
|
1358
|
+
}
|
|
1359
|
+
if (lower === "stop_sequence") {
|
|
1360
|
+
return "completed";
|
|
1361
|
+
}
|
|
1362
|
+
return super.normalizeFinishReason(providerReason);
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
|
|
1185
1366
|
// src/llm-service.js
|
|
1186
1367
|
var LLMService = class {
|
|
1187
1368
|
constructor(env, toolImplementations = {}) {
|
|
@@ -1203,6 +1384,8 @@ var LLMService = class {
|
|
|
1203
1384
|
provider = new OpenAIProvider(config);
|
|
1204
1385
|
} else if (config.provider === "gemini" || config.provider === "vertex") {
|
|
1205
1386
|
provider = new GoogleProvider(config);
|
|
1387
|
+
} else if (config.provider === "anthropic") {
|
|
1388
|
+
provider = new AnthropicProvider(config);
|
|
1206
1389
|
} else {
|
|
1207
1390
|
throw new LLMServiceException(`Unsupported LLM provider: ${config.provider}`, 500);
|
|
1208
1391
|
}
|
|
@@ -1771,6 +1954,7 @@ function createSpeechHandler(app, getConfig) {
|
|
|
1771
1954
|
}
|
|
1772
1955
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1773
1956
|
0 && (module.exports = {
|
|
1957
|
+
AnthropicProvider,
|
|
1774
1958
|
BaseConfigProvider,
|
|
1775
1959
|
ConfigManager,
|
|
1776
1960
|
DefaultConfigProvider,
|