@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/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-5-sonnet-latest",
17
- DEFAULT: "claude-3-5-sonnet-latest",
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
- DEFAULT: "gpt-4o",
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: zodResponseFormat(zodSchema, "response"),
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
- const schema = options.response instanceof z.ZodType
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 this.createTextCompletion(client, messages, modelToUse, systemMessage);
1629
+ return createTextCompletion(client, messages, modelToUse, systemMessage);
1323
1630
  }
1324
- // Placeholder for operate method - will be implemented in a future task
1325
- // This will be properly implemented in the "Tool Calling Implementation" task
1326
- async operate(input, _options = {}) {
1327
- throw new Error("The operate method is not yet implemented for AnthropicProvider");
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 toolkit = new Toolkit([random, roll, time, weather]);
1639
- const tools = toolkit.tools;
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