@jaypie/llm 1.1.21 → 1.1.23
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/constants.d.ts +38 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +429 -108
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic/AnthropicProvider.class.d.ts +15 -0
- package/dist/providers/anthropic/operate.d.ts +16 -0
- package/dist/providers/anthropic/utils.d.ts +7 -3
- package/dist/providers/openai/utils.d.ts +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/util/naturalZodSchema.d.ts +1 -1
- package/package.json +6 -5
- package/dist/providers/AnthropicProvider.class.d.ts +0 -20
package/dist/index.js
CHANGED
|
@@ -2,19 +2,40 @@ import { ConfigurationError, BadGatewayError, TooManyRequestsError, NotImplement
|
|
|
2
2
|
import { log as log$2, JAYPIE, resolveValue, placeholders, sleep, ConfigurationError as ConfigurationError$1 } from '@jaypie/core';
|
|
3
3
|
import { OpenAI, APIUserAbortError, AuthenticationError, BadRequestError, ConflictError, NotFoundError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, APIConnectionError, APIConnectionTimeoutError, InternalServerError } from 'openai';
|
|
4
4
|
import { zodResponseFormat } from 'openai/helpers/zod';
|
|
5
|
-
import { z } from 'zod';
|
|
5
|
+
import { z } from 'zod/v4';
|
|
6
6
|
import RandomLib from 'random';
|
|
7
7
|
import { getEnvSecret } from '@jaypie/aws';
|
|
8
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
8
|
+
import Anthropic$1, { Anthropic } from '@anthropic-ai/sdk';
|
|
9
|
+
import ZSchema from 'z-schema';
|
|
9
10
|
import { fetchWeatherApi } from 'openmeteo';
|
|
10
11
|
|
|
11
12
|
const PROVIDER = {
|
|
12
13
|
ANTHROPIC: {
|
|
14
|
+
// https://docs.anthropic.com/en/docs/about-claude/models/overview
|
|
13
15
|
MODEL: {
|
|
16
|
+
// Jaypie Aliases
|
|
17
|
+
DEFAULT: "claude-sonnet-4-0",
|
|
18
|
+
SMALL: "claude-3-5-haiku-latest",
|
|
19
|
+
TINY: "claude-3-5-haiku-latest",
|
|
20
|
+
LARGE: "claude-opus-4-0",
|
|
21
|
+
JUMBO: "claude-opus-4-0",
|
|
22
|
+
// Latests
|
|
23
|
+
CLAUDE_OPUS_4: "claude-opus-4-0",
|
|
24
|
+
CLAUDE_SONNET_4: "claude-sonnet-4-0",
|
|
14
25
|
CLAUDE_3_HAIKU: "claude-3-5-haiku-latest",
|
|
15
26
|
CLAUDE_3_OPUS: "claude-3-opus-latest",
|
|
16
|
-
CLAUDE_3_SONNET: "claude-3-
|
|
17
|
-
|
|
27
|
+
CLAUDE_3_SONNET: "claude-3-7-sonnet-latest",
|
|
28
|
+
// Specifics
|
|
29
|
+
CLAUDE_OPUS_4_0: "claude-opus-4-0",
|
|
30
|
+
CLAUDE_SONNET_4_0: "claude-sonnet-4-0",
|
|
31
|
+
CLAUDE_3_7_SONNET: "claude-3-7-sonnet-latest ",
|
|
32
|
+
CLAUDE_3_5_SONNET: "claude-3-5-sonnet-latest",
|
|
33
|
+
CLAUDE_3_5_HAIKU: "claude-3-5-haiku-latest",
|
|
34
|
+
// _Note: Claude reversed the order of model name and version in 4_
|
|
35
|
+
// Backward compatibility
|
|
36
|
+
CLAUDE_HAIKU_3: "claude-3-5-haiku-latest",
|
|
37
|
+
CLAUDE_OPUS_3: "claude-3-opus-latest",
|
|
38
|
+
CLAUDE_SONNET_3: "claude-3-7-sonnet-latest",
|
|
18
39
|
},
|
|
19
40
|
NAME: "anthropic",
|
|
20
41
|
PROMPT: {
|
|
@@ -34,8 +55,18 @@ const PROVIDER = {
|
|
|
34
55
|
},
|
|
35
56
|
},
|
|
36
57
|
OPENAI: {
|
|
58
|
+
// https://platform.openai.com/docs/models
|
|
37
59
|
MODEL: {
|
|
38
|
-
|
|
60
|
+
// Jaypie Aliases
|
|
61
|
+
DEFAULT: "gpt-4.1",
|
|
62
|
+
SMALL: "gpt-4.1-mini",
|
|
63
|
+
LARGE: "o3",
|
|
64
|
+
TINY: "gpt-4.1-nano",
|
|
65
|
+
JUMBO: "o3-pro",
|
|
66
|
+
// OpenAI Official
|
|
67
|
+
GPT_4_1: "gpt-4.1",
|
|
68
|
+
GPT_4_1_MINI: "gpt-4.1-mini",
|
|
69
|
+
GPT_4_1_NANO: "gpt-4.1-nano",
|
|
39
70
|
GPT_4: "gpt-4",
|
|
40
71
|
GPT_4_O_MINI: "gpt-4o-mini",
|
|
41
72
|
GPT_4_O: "gpt-4o",
|
|
@@ -45,6 +76,9 @@ const PROVIDER = {
|
|
|
45
76
|
O1_PRO: "o1-pro",
|
|
46
77
|
O3_MINI: "o3-mini",
|
|
47
78
|
O3_MINI_HIGH: "o3-mini-high",
|
|
79
|
+
O3: "o3",
|
|
80
|
+
O3_PRO: "o3-pro",
|
|
81
|
+
O4_MINI: "o4-mini",
|
|
48
82
|
},
|
|
49
83
|
NAME: "openai",
|
|
50
84
|
},
|
|
@@ -668,11 +702,26 @@ function createRequestOptions(input, options = {}) {
|
|
|
668
702
|
? options.format
|
|
669
703
|
: naturalZodSchema(options.format);
|
|
670
704
|
const responseFormat = zodResponseFormat(zodSchema, "response");
|
|
705
|
+
const jsonSchema = z.toJSONSchema(zodSchema);
|
|
706
|
+
// Temporary hack because of OpenAI requires additional_properties to be false on all objects
|
|
707
|
+
const checks = [jsonSchema];
|
|
708
|
+
while (checks.length > 0) {
|
|
709
|
+
const current = checks[0];
|
|
710
|
+
if (current.type == "object") {
|
|
711
|
+
current.additionalProperties = false;
|
|
712
|
+
}
|
|
713
|
+
Object.keys(current).forEach((key) => {
|
|
714
|
+
if (typeof current[key] == "object") {
|
|
715
|
+
checks.push(current[key]);
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
checks.shift();
|
|
719
|
+
}
|
|
671
720
|
// Set up structured output format in the format expected by the test
|
|
672
721
|
requestOptions.text = {
|
|
673
722
|
format: {
|
|
674
723
|
name: responseFormat.json_schema.name,
|
|
675
|
-
schema: responseFormat.json_schema.schema
|
|
724
|
+
schema: jsonSchema, // Replace this with responseFormat.json_schema.schema once OpenAI supports Zod v4
|
|
676
725
|
strict: responseFormat.json_schema.strict,
|
|
677
726
|
type: responseFormat.type,
|
|
678
727
|
},
|
|
@@ -701,7 +750,7 @@ function createRequestOptions(input, options = {}) {
|
|
|
701
750
|
//
|
|
702
751
|
// Main
|
|
703
752
|
//
|
|
704
|
-
async function operate(input, options = {}, context = {
|
|
753
|
+
async function operate$1(input, options = {}, context = {
|
|
705
754
|
client: new OpenAI(),
|
|
706
755
|
}) {
|
|
707
756
|
//
|
|
@@ -1080,21 +1129,38 @@ function prepareMessages$1(message, { system, data, placeholders } = {}) {
|
|
|
1080
1129
|
return messages;
|
|
1081
1130
|
}
|
|
1082
1131
|
// Completion requests
|
|
1083
|
-
async function createStructuredCompletion(client, { messages, responseSchema, model, }) {
|
|
1132
|
+
async function createStructuredCompletion$1(client, { messages, responseSchema, model, }) {
|
|
1084
1133
|
const logger = getLogger$1();
|
|
1085
1134
|
logger.trace("Using structured output");
|
|
1086
1135
|
const zodSchema = responseSchema instanceof z.ZodType
|
|
1087
1136
|
? responseSchema
|
|
1088
1137
|
: naturalZodSchema(responseSchema);
|
|
1138
|
+
const responseFormat = zodResponseFormat(zodSchema, "response");
|
|
1139
|
+
const jsonSchema = z.toJSONSchema(zodSchema);
|
|
1140
|
+
// Temporary hack because OpenAI requires additional_properties to be false on all objects
|
|
1141
|
+
const checks = [jsonSchema];
|
|
1142
|
+
while (checks.length > 0) {
|
|
1143
|
+
const current = checks[0];
|
|
1144
|
+
if (current.type == "object") {
|
|
1145
|
+
current.additionalProperties = false;
|
|
1146
|
+
}
|
|
1147
|
+
Object.keys(current).forEach((key) => {
|
|
1148
|
+
if (typeof current[key] == "object") {
|
|
1149
|
+
checks.push(current[key]);
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
checks.shift();
|
|
1153
|
+
}
|
|
1154
|
+
responseFormat.json_schema.schema = jsonSchema;
|
|
1089
1155
|
const completion = await client.beta.chat.completions.parse({
|
|
1090
1156
|
messages,
|
|
1091
1157
|
model,
|
|
1092
|
-
response_format:
|
|
1158
|
+
response_format: responseFormat,
|
|
1093
1159
|
});
|
|
1094
1160
|
logger.var({ assistantReply: completion.choices[0].message.parsed });
|
|
1095
1161
|
return completion.choices[0].message.parsed;
|
|
1096
1162
|
}
|
|
1097
|
-
async function createTextCompletion(client, { messages, model, }) {
|
|
1163
|
+
async function createTextCompletion$1(client, { messages, model, }) {
|
|
1098
1164
|
const logger = getLogger$1();
|
|
1099
1165
|
logger.trace("Using text output (unstructured)");
|
|
1100
1166
|
const completion = await client.chat.completions.create({
|
|
@@ -1124,13 +1190,13 @@ class OpenAiProvider {
|
|
|
1124
1190
|
const messages = prepareMessages$1(message, options || {});
|
|
1125
1191
|
const modelToUse = options?.model || this.model;
|
|
1126
1192
|
if (options?.response) {
|
|
1127
|
-
return createStructuredCompletion(client, {
|
|
1193
|
+
return createStructuredCompletion$1(client, {
|
|
1128
1194
|
messages,
|
|
1129
1195
|
responseSchema: options.response,
|
|
1130
1196
|
model: modelToUse,
|
|
1131
1197
|
});
|
|
1132
1198
|
}
|
|
1133
|
-
return createTextCompletion(client, {
|
|
1199
|
+
return createTextCompletion$1(client, {
|
|
1134
1200
|
messages,
|
|
1135
1201
|
model: modelToUse,
|
|
1136
1202
|
});
|
|
@@ -1147,7 +1213,7 @@ class OpenAiProvider {
|
|
|
1147
1213
|
: [...this.conversationHistory];
|
|
1148
1214
|
}
|
|
1149
1215
|
// Call operate with the updated options
|
|
1150
|
-
const response = await operate(input, mergedOptions, { client });
|
|
1216
|
+
const response = await operate$1(input, mergedOptions, { client });
|
|
1151
1217
|
// Update conversation history with the new history from the response
|
|
1152
1218
|
if (response.history && response.history.length > 0) {
|
|
1153
1219
|
this.conversationHistory = response.history;
|
|
@@ -1156,6 +1222,267 @@ class OpenAiProvider {
|
|
|
1156
1222
|
}
|
|
1157
1223
|
}
|
|
1158
1224
|
|
|
1225
|
+
// Handle placeholder logic
|
|
1226
|
+
// Convert string input to array format if needed
|
|
1227
|
+
// Apply placeholders to fields if data is provided and placeholders.* is undefined or true
|
|
1228
|
+
function handleInputAndPlaceholders(input, options) {
|
|
1229
|
+
let history = formatOperateInput(input);
|
|
1230
|
+
let llmInstructions;
|
|
1231
|
+
let systemPrompt;
|
|
1232
|
+
if (options?.data &&
|
|
1233
|
+
(options.placeholders?.input === undefined || options.placeholders?.input)) {
|
|
1234
|
+
history = formatOperateInput(input, {
|
|
1235
|
+
data: options?.data,
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
if (options?.instructions) {
|
|
1239
|
+
llmInstructions =
|
|
1240
|
+
options.data && options.placeholders?.instructions !== false
|
|
1241
|
+
? placeholders(options.instructions, options.data)
|
|
1242
|
+
: options.instructions;
|
|
1243
|
+
}
|
|
1244
|
+
if (options?.system) {
|
|
1245
|
+
systemPrompt =
|
|
1246
|
+
options.data && options.placeholders?.system !== false
|
|
1247
|
+
? placeholders(options.system, options.data)
|
|
1248
|
+
: options.system;
|
|
1249
|
+
}
|
|
1250
|
+
return { history, systemPrompt, llmInstructions };
|
|
1251
|
+
}
|
|
1252
|
+
function updateUsage(usage, totalUsage) {
|
|
1253
|
+
totalUsage.input += usage.input_tokens;
|
|
1254
|
+
totalUsage.output += usage.output_tokens;
|
|
1255
|
+
totalUsage.reasoning += usage.prompt_tokens;
|
|
1256
|
+
totalUsage.total += usage.input_tokens + usage.output_tokens;
|
|
1257
|
+
}
|
|
1258
|
+
function handleMaxTurns(maxTurns, history, inputMessages, response, totalUsage) {
|
|
1259
|
+
const error = new TooManyRequestsError();
|
|
1260
|
+
const detail = `Model requested function call but exceeded ${maxTurns} turns`;
|
|
1261
|
+
log.warn(detail);
|
|
1262
|
+
return {
|
|
1263
|
+
//model: model,
|
|
1264
|
+
//provider: PROVIDER.ANTHROPIC,
|
|
1265
|
+
error: {
|
|
1266
|
+
detail,
|
|
1267
|
+
status: error.status,
|
|
1268
|
+
title: error.title,
|
|
1269
|
+
},
|
|
1270
|
+
history,
|
|
1271
|
+
output: inputMessages.slice(-1),
|
|
1272
|
+
responses: response.content,
|
|
1273
|
+
status: LlmResponseStatus.Incomplete,
|
|
1274
|
+
usage: [totalUsage],
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
function handleOutputSchema(format) {
|
|
1278
|
+
let schema;
|
|
1279
|
+
if (format) {
|
|
1280
|
+
// Check if format is a JsonObject with type "json_schema"
|
|
1281
|
+
if (typeof format === "object" &&
|
|
1282
|
+
format !== null &&
|
|
1283
|
+
!Array.isArray(format) &&
|
|
1284
|
+
format.type === "json_schema") {
|
|
1285
|
+
// Direct pass-through for JsonObject with type "json_schema"
|
|
1286
|
+
schema = structuredClone(format);
|
|
1287
|
+
schema.type = "object"; // Validator does not recognise "json_schema" as a type
|
|
1288
|
+
}
|
|
1289
|
+
else {
|
|
1290
|
+
// Convert NaturalSchema to JSON schema through Zod
|
|
1291
|
+
const zodSchema = format instanceof z.ZodType
|
|
1292
|
+
? format
|
|
1293
|
+
: naturalZodSchema(format);
|
|
1294
|
+
schema = z.toJSONSchema(zodSchema);
|
|
1295
|
+
}
|
|
1296
|
+
if (schema.$schema) {
|
|
1297
|
+
delete schema.$schema; // Hack to fix issue with validator
|
|
1298
|
+
}
|
|
1299
|
+
return schema;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
// Register tools and process them to work with Anthropic
|
|
1303
|
+
function bundleTools(tools, explain, schema) {
|
|
1304
|
+
let toolkit;
|
|
1305
|
+
let processedTools = [];
|
|
1306
|
+
if (tools instanceof Toolkit) {
|
|
1307
|
+
toolkit = tools;
|
|
1308
|
+
}
|
|
1309
|
+
else if (Array.isArray(tools)) {
|
|
1310
|
+
toolkit = new Toolkit(tools, { explain });
|
|
1311
|
+
}
|
|
1312
|
+
if (toolkit) {
|
|
1313
|
+
toolkit.tools.forEach((tool) => {
|
|
1314
|
+
processedTools.push({
|
|
1315
|
+
...tool,
|
|
1316
|
+
input_schema: {
|
|
1317
|
+
...tool.parameters,
|
|
1318
|
+
type: "object",
|
|
1319
|
+
},
|
|
1320
|
+
type: "custom",
|
|
1321
|
+
});
|
|
1322
|
+
delete processedTools[processedTools.length - 1].parameters;
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
if (schema) {
|
|
1326
|
+
processedTools.push({
|
|
1327
|
+
name: "structured_output",
|
|
1328
|
+
description: "Output a structured JSON object, " +
|
|
1329
|
+
"use this before your final response to give structured outputs to the user",
|
|
1330
|
+
input_schema: schema,
|
|
1331
|
+
type: "custom",
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
return { processedTools, toolkit };
|
|
1335
|
+
}
|
|
1336
|
+
// Handles individual tool calls. Returns true for break, false for continue.
|
|
1337
|
+
async function callTool(inputMessages, response, hooks, toolkit) {
|
|
1338
|
+
inputMessages.push({
|
|
1339
|
+
role: PROVIDER.ANTHROPIC.ROLE.ASSISTANT,
|
|
1340
|
+
content: response.content,
|
|
1341
|
+
});
|
|
1342
|
+
// Get the tool use
|
|
1343
|
+
const toolUse = response.content[response.content.length - 1];
|
|
1344
|
+
// If the tool use is structured output (magic tool), break
|
|
1345
|
+
if (toolUse.name === "structured_output") {
|
|
1346
|
+
return true;
|
|
1347
|
+
}
|
|
1348
|
+
if (hooks?.beforeEachTool) {
|
|
1349
|
+
await hooks.beforeEachTool({
|
|
1350
|
+
toolName: toolUse.name,
|
|
1351
|
+
args: JSON.stringify(toolUse.input),
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
let result;
|
|
1355
|
+
try {
|
|
1356
|
+
result = await toolkit?.call({
|
|
1357
|
+
name: toolUse.name,
|
|
1358
|
+
arguments: JSON.stringify(toolUse.input),
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
catch (error) {
|
|
1362
|
+
if (hooks?.onToolError) {
|
|
1363
|
+
await hooks.onToolError({
|
|
1364
|
+
error: error,
|
|
1365
|
+
toolName: toolUse.name,
|
|
1366
|
+
args: JSON.stringify(toolUse.input),
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
throw error;
|
|
1370
|
+
}
|
|
1371
|
+
if (hooks?.afterEachTool) {
|
|
1372
|
+
await hooks.afterEachTool({
|
|
1373
|
+
result,
|
|
1374
|
+
toolName: toolUse.name,
|
|
1375
|
+
args: JSON.stringify(toolUse.input),
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
inputMessages.push({
|
|
1379
|
+
role: PROVIDER.ANTHROPIC.ROLE.USER,
|
|
1380
|
+
content: [
|
|
1381
|
+
{
|
|
1382
|
+
type: "tool_result",
|
|
1383
|
+
content: JSON.stringify(result),
|
|
1384
|
+
tool_use_id: toolUse.id,
|
|
1385
|
+
},
|
|
1386
|
+
],
|
|
1387
|
+
});
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
//
|
|
1391
|
+
//
|
|
1392
|
+
// Main
|
|
1393
|
+
//
|
|
1394
|
+
async function operate(input, options = {}, context = {
|
|
1395
|
+
client: new Anthropic(),
|
|
1396
|
+
}) {
|
|
1397
|
+
// Set model
|
|
1398
|
+
const model = options?.model || PROVIDER.ANTHROPIC.MODEL.DEFAULT;
|
|
1399
|
+
let schema = handleOutputSchema(options.format);
|
|
1400
|
+
let { processedTools, toolkit } = bundleTools(options.tools, options.explain, schema);
|
|
1401
|
+
let { history, systemPrompt, llmInstructions } = handleInputAndPlaceholders(input, options);
|
|
1402
|
+
// If history is provided, merge it with the input
|
|
1403
|
+
if (options.history) {
|
|
1404
|
+
history = [...options.history, ...history];
|
|
1405
|
+
}
|
|
1406
|
+
// Avoid Anthropic error by removing type property
|
|
1407
|
+
const inputMessages = structuredClone(history);
|
|
1408
|
+
inputMessages.forEach((message) => {
|
|
1409
|
+
delete message.type;
|
|
1410
|
+
});
|
|
1411
|
+
// Add instruction to the input message
|
|
1412
|
+
if (llmInstructions) {
|
|
1413
|
+
inputMessages[inputMessages.length - 1].content += "\n\n" + llmInstructions;
|
|
1414
|
+
}
|
|
1415
|
+
// Setup usage tracking
|
|
1416
|
+
let totalUsage = {
|
|
1417
|
+
input: 0,
|
|
1418
|
+
output: 0,
|
|
1419
|
+
reasoning: 0,
|
|
1420
|
+
total: 0,
|
|
1421
|
+
};
|
|
1422
|
+
// Determine max turns from options
|
|
1423
|
+
const maxTurns = maxTurnsFromOptions(options);
|
|
1424
|
+
const enableMultipleTurns = maxTurns > 1;
|
|
1425
|
+
let currentTurn = 0;
|
|
1426
|
+
let response;
|
|
1427
|
+
while (true) {
|
|
1428
|
+
// Loop for tool use
|
|
1429
|
+
response = await context.client.messages.create({
|
|
1430
|
+
model: model,
|
|
1431
|
+
system: systemPrompt,
|
|
1432
|
+
messages: inputMessages,
|
|
1433
|
+
max_tokens: PROVIDER.ANTHROPIC.MAX_TOKENS.DEFAULT,
|
|
1434
|
+
stream: false,
|
|
1435
|
+
tools: processedTools,
|
|
1436
|
+
tool_choice: processedTools.length > 0
|
|
1437
|
+
? { type: schema ? "any" : "auto" }
|
|
1438
|
+
: undefined,
|
|
1439
|
+
...options?.providerOptions,
|
|
1440
|
+
});
|
|
1441
|
+
// Update usage
|
|
1442
|
+
updateUsage(response.usage, totalUsage);
|
|
1443
|
+
// If the response is not a tool use, break
|
|
1444
|
+
if (response.stop_reason !== "tool_use") {
|
|
1445
|
+
break;
|
|
1446
|
+
}
|
|
1447
|
+
const breakLoop = await callTool(inputMessages, response, options.hooks, toolkit);
|
|
1448
|
+
if (breakLoop) {
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1451
|
+
// Handle turn limit
|
|
1452
|
+
if (!enableMultipleTurns || currentTurn >= maxTurns) {
|
|
1453
|
+
return handleMaxTurns(maxTurns, history, inputMessages, response, totalUsage);
|
|
1454
|
+
}
|
|
1455
|
+
currentTurn++;
|
|
1456
|
+
}
|
|
1457
|
+
let jsonResult;
|
|
1458
|
+
if (schema) {
|
|
1459
|
+
const validator = new ZSchema({});
|
|
1460
|
+
jsonResult = response.content[response.content.length - 1].input;
|
|
1461
|
+
if (!validator.validate(jsonResult, schema)) {
|
|
1462
|
+
throw new Error("Model returned invalid JSON");
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
history.push({
|
|
1466
|
+
content: schema
|
|
1467
|
+
? JSON.stringify(jsonResult)
|
|
1468
|
+
: response.content[0].text,
|
|
1469
|
+
role: PROVIDER.ANTHROPIC.ROLE.ASSISTANT,
|
|
1470
|
+
type: LlmMessageType.Message,
|
|
1471
|
+
});
|
|
1472
|
+
return {
|
|
1473
|
+
//model: model,
|
|
1474
|
+
//provider: PROVIDER.ANTHROPIC,
|
|
1475
|
+
content: schema
|
|
1476
|
+
? jsonResult
|
|
1477
|
+
: response.content[0].text,
|
|
1478
|
+
responses: [response],
|
|
1479
|
+
output: history.slice(-1),
|
|
1480
|
+
history,
|
|
1481
|
+
status: LlmResponseStatus.Completed,
|
|
1482
|
+
usage: [totalUsage],
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1159
1486
|
// Logger
|
|
1160
1487
|
const getLogger = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
1161
1488
|
// Client initialization
|
|
@@ -1165,7 +1492,7 @@ async function initializeClient({ apiKey, } = {}) {
|
|
|
1165
1492
|
if (!resolvedApiKey) {
|
|
1166
1493
|
throw new ConfigurationError$1("The application could not resolve the required API key: ANTHROPIC_API_KEY");
|
|
1167
1494
|
}
|
|
1168
|
-
const client = new Anthropic({ apiKey: resolvedApiKey });
|
|
1495
|
+
const client = new Anthropic$1({ apiKey: resolvedApiKey });
|
|
1169
1496
|
logger.trace("Initialized Anthropic client");
|
|
1170
1497
|
return client;
|
|
1171
1498
|
}
|
|
@@ -1193,6 +1520,72 @@ function prepareMessages(message, { data, placeholders } = {}) {
|
|
|
1193
1520
|
logger.trace(`User message: ${userMessage.content.length} characters`);
|
|
1194
1521
|
return messages;
|
|
1195
1522
|
}
|
|
1523
|
+
// Basic text completion
|
|
1524
|
+
async function createTextCompletion(client, messages, model, systemMessage) {
|
|
1525
|
+
log$2.trace("Using text output (unstructured)");
|
|
1526
|
+
const params = {
|
|
1527
|
+
model,
|
|
1528
|
+
messages,
|
|
1529
|
+
max_tokens: PROVIDER.ANTHROPIC.MAX_TOKENS.DEFAULT,
|
|
1530
|
+
};
|
|
1531
|
+
// Add system instruction if provided
|
|
1532
|
+
if (systemMessage) {
|
|
1533
|
+
params.system = systemMessage;
|
|
1534
|
+
log$2.trace(`System message: ${systemMessage.length} characters`);
|
|
1535
|
+
}
|
|
1536
|
+
const response = await client.messages.create(params);
|
|
1537
|
+
log$2.trace(`Assistant reply: ${response.content[0]?.text?.length || 0} characters`);
|
|
1538
|
+
return response.content[0]?.text || "";
|
|
1539
|
+
}
|
|
1540
|
+
// Structured output completion
|
|
1541
|
+
async function createStructuredCompletion(client, messages, model, responseSchema, systemMessage) {
|
|
1542
|
+
log$2.trace("Using structured output");
|
|
1543
|
+
// Get the JSON schema for the response
|
|
1544
|
+
const schema = responseSchema instanceof z.ZodType
|
|
1545
|
+
? responseSchema
|
|
1546
|
+
: naturalZodSchema(responseSchema);
|
|
1547
|
+
// Set system message with JSON instructions
|
|
1548
|
+
const defaultSystemPrompt = "You will be responding with structured JSON data. " +
|
|
1549
|
+
"Format your entire response as a valid JSON object with the following structure: " +
|
|
1550
|
+
JSON.stringify(z.toJSONSchema(schema));
|
|
1551
|
+
const systemPrompt = systemMessage || defaultSystemPrompt;
|
|
1552
|
+
try {
|
|
1553
|
+
// Use standard Anthropic API to get response
|
|
1554
|
+
const params = {
|
|
1555
|
+
model,
|
|
1556
|
+
messages,
|
|
1557
|
+
max_tokens: PROVIDER.ANTHROPIC.MAX_TOKENS.DEFAULT,
|
|
1558
|
+
system: systemPrompt,
|
|
1559
|
+
};
|
|
1560
|
+
const response = await client.messages.create(params);
|
|
1561
|
+
// Extract text from response
|
|
1562
|
+
const responseText = response.content[0]?.text || "";
|
|
1563
|
+
// Find JSON in response
|
|
1564
|
+
const jsonMatch = responseText.match(/```json\s*([\s\S]*?)\s*```/) ||
|
|
1565
|
+
responseText.match(/\{[\s\S]*\}/);
|
|
1566
|
+
if (jsonMatch) {
|
|
1567
|
+
try {
|
|
1568
|
+
// Parse the JSON response
|
|
1569
|
+
const jsonStr = jsonMatch[1] || jsonMatch[0];
|
|
1570
|
+
const result = JSON.parse(jsonStr);
|
|
1571
|
+
if (!schema.parse(result)) {
|
|
1572
|
+
throw new Error(`JSON response from Anthropic does not match schema: ${responseText}`);
|
|
1573
|
+
}
|
|
1574
|
+
log$2.trace("Received structured response", { result });
|
|
1575
|
+
return result;
|
|
1576
|
+
}
|
|
1577
|
+
catch {
|
|
1578
|
+
throw new Error(`Failed to parse JSON response from Anthropic: ${responseText}`);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
// If we can't extract JSON
|
|
1582
|
+
throw new Error("Failed to parse structured response from Anthropic");
|
|
1583
|
+
}
|
|
1584
|
+
catch (error) {
|
|
1585
|
+
log$2.error("Error creating structured completion", { error });
|
|
1586
|
+
throw error;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1196
1589
|
|
|
1197
1590
|
// Maps Jaypie roles to Anthropic roles
|
|
1198
1591
|
({
|
|
@@ -1217,89 +1610,6 @@ class AnthropicProvider {
|
|
|
1217
1610
|
this._client = await initializeClient({ apiKey: this.apiKey });
|
|
1218
1611
|
return this._client;
|
|
1219
1612
|
}
|
|
1220
|
-
// Basic text completion
|
|
1221
|
-
async createTextCompletion(client, messages, model, systemMessage) {
|
|
1222
|
-
this.log.trace("Using text output (unstructured)");
|
|
1223
|
-
const params = {
|
|
1224
|
-
model,
|
|
1225
|
-
messages,
|
|
1226
|
-
max_tokens: PROVIDER.ANTHROPIC.MAX_TOKENS.DEFAULT,
|
|
1227
|
-
};
|
|
1228
|
-
// Add system instruction if provided
|
|
1229
|
-
if (systemMessage) {
|
|
1230
|
-
params.system = systemMessage;
|
|
1231
|
-
this.log.trace(`System message: ${systemMessage.length} characters`);
|
|
1232
|
-
}
|
|
1233
|
-
const response = await client.messages.create(params);
|
|
1234
|
-
this.log.trace(`Assistant reply: ${response.content[0]?.text?.length || 0} characters`);
|
|
1235
|
-
return response.content[0]?.text || "";
|
|
1236
|
-
}
|
|
1237
|
-
// Structured output completion
|
|
1238
|
-
async createStructuredCompletion(client, messages, model, responseSchema, systemMessage) {
|
|
1239
|
-
this.log.trace("Using structured output");
|
|
1240
|
-
// Get the JSON schema for the response
|
|
1241
|
-
const schema = responseSchema instanceof z.ZodType
|
|
1242
|
-
? responseSchema
|
|
1243
|
-
: naturalZodSchema(responseSchema);
|
|
1244
|
-
// Set system message with JSON instructions
|
|
1245
|
-
const defaultSystemPrompt = "You will be responding with structured JSON data. " +
|
|
1246
|
-
"Format your entire response as a valid JSON object with the following structure: " +
|
|
1247
|
-
(responseSchema instanceof z.ZodType
|
|
1248
|
-
? JSON.stringify(this.simplifyZodSchema(schema))
|
|
1249
|
-
: JSON.stringify(responseSchema));
|
|
1250
|
-
const systemPrompt = systemMessage || defaultSystemPrompt;
|
|
1251
|
-
try {
|
|
1252
|
-
// Use standard Anthropic API to get response
|
|
1253
|
-
const params = {
|
|
1254
|
-
model,
|
|
1255
|
-
messages,
|
|
1256
|
-
max_tokens: PROVIDER.ANTHROPIC.MAX_TOKENS.DEFAULT,
|
|
1257
|
-
system: systemPrompt,
|
|
1258
|
-
};
|
|
1259
|
-
const response = await client.messages.create(params);
|
|
1260
|
-
// Extract text from response
|
|
1261
|
-
const responseText = response.content[0]?.text || "";
|
|
1262
|
-
// Find JSON in response
|
|
1263
|
-
const jsonMatch = responseText.match(/```json\s*([\s\S]*?)\s*```/) ||
|
|
1264
|
-
responseText.match(/\{[\s\S]*\}/);
|
|
1265
|
-
if (jsonMatch) {
|
|
1266
|
-
try {
|
|
1267
|
-
// Parse the JSON response
|
|
1268
|
-
const jsonStr = jsonMatch[1] || jsonMatch[0];
|
|
1269
|
-
const result = JSON.parse(jsonStr);
|
|
1270
|
-
this.log.trace("Received structured response", { result });
|
|
1271
|
-
return result;
|
|
1272
|
-
}
|
|
1273
|
-
catch {
|
|
1274
|
-
throw new Error(`Failed to parse JSON response from Anthropic: ${responseText}`);
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
// If we can't extract JSON
|
|
1278
|
-
throw new Error("Failed to parse structured response from Anthropic");
|
|
1279
|
-
}
|
|
1280
|
-
catch (error) {
|
|
1281
|
-
this.log.error("Error creating structured completion", { error });
|
|
1282
|
-
throw error;
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
// Helper method to simplify Zod schema to a plain object for system prompt
|
|
1286
|
-
simplifyZodSchema(schema) {
|
|
1287
|
-
try {
|
|
1288
|
-
const zodSchema = schema;
|
|
1289
|
-
if (typeof zodSchema._def?.shape === "object") {
|
|
1290
|
-
const result = {};
|
|
1291
|
-
Object.keys(zodSchema._def.shape || {}).forEach((key) => {
|
|
1292
|
-
result[key] = "string";
|
|
1293
|
-
});
|
|
1294
|
-
return result;
|
|
1295
|
-
}
|
|
1296
|
-
return { result: "string" };
|
|
1297
|
-
}
|
|
1298
|
-
catch (error) {
|
|
1299
|
-
this.log.error(`Error simplifying schema: ${error}`);
|
|
1300
|
-
return { result: "string" };
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
1613
|
// Main send method
|
|
1304
1614
|
async send(message, options) {
|
|
1305
1615
|
const client = await this.getClient();
|
|
@@ -1314,17 +1624,28 @@ class AnthropicProvider {
|
|
|
1314
1624
|
});
|
|
1315
1625
|
}
|
|
1316
1626
|
if (options?.response) {
|
|
1317
|
-
|
|
1318
|
-
? options.response
|
|
1319
|
-
: naturalZodSchema(options.response);
|
|
1320
|
-
return this.createStructuredCompletion(client, messages, modelToUse, schema, systemMessage);
|
|
1627
|
+
return createStructuredCompletion(client, messages, modelToUse, options.response, systemMessage);
|
|
1321
1628
|
}
|
|
1322
|
-
return
|
|
1629
|
+
return createTextCompletion(client, messages, modelToUse, systemMessage);
|
|
1323
1630
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1631
|
+
async operate(input, options = {}) {
|
|
1632
|
+
const client = await this.getClient();
|
|
1633
|
+
options.model = options?.model || this.model;
|
|
1634
|
+
// Create a merged history including both the tracked history and any explicitly provided history
|
|
1635
|
+
const mergedOptions = { ...options };
|
|
1636
|
+
if (this.conversationHistory.length > 0) {
|
|
1637
|
+
// If options.history exists, merge with instance history, otherwise use instance history
|
|
1638
|
+
mergedOptions.history = options.history
|
|
1639
|
+
? [...this.conversationHistory, ...options.history]
|
|
1640
|
+
: [...this.conversationHistory];
|
|
1641
|
+
}
|
|
1642
|
+
// Call operate with the updated options
|
|
1643
|
+
const response = await operate(input, mergedOptions, { client });
|
|
1644
|
+
// Update conversation history with the new history from the response
|
|
1645
|
+
if (response.history && response.history.length > 0) {
|
|
1646
|
+
this.conversationHistory = response.history;
|
|
1647
|
+
}
|
|
1648
|
+
return response;
|
|
1328
1649
|
}
|
|
1329
1650
|
}
|
|
1330
1651
|
|
|
@@ -1635,8 +1956,8 @@ const weather = {
|
|
|
1635
1956
|
},
|
|
1636
1957
|
};
|
|
1637
1958
|
|
|
1638
|
-
const
|
|
1639
|
-
const
|
|
1959
|
+
const tools = [random, roll, time, weather];
|
|
1960
|
+
const toolkit = new Toolkit(tools);
|
|
1640
1961
|
|
|
1641
1962
|
export { constants as LLM, Llm, Toolkit, toolkit, tools };
|
|
1642
1963
|
//# sourceMappingURL=index.js.map
|