@agentica/core 0.45.0-dev.20260426 → 0.45.1

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/lib/index.mjs CHANGED
@@ -1083,12 +1083,12 @@ function accumulate(origin, chunk) {
1083
1083
  };
1084
1084
  }
1085
1085
 
1086
- function merge(chunks) {
1086
+ function mergeChunks(chunks) {
1087
1087
  const firstChunk = chunks[0];
1088
1088
  if (firstChunk === undefined) {
1089
1089
  throw new Error("No chunks received");
1090
1090
  }
1091
- const result = chunks.reduce(accumulate, {
1091
+ return chunks.reduce(accumulate, {
1092
1092
  id: firstChunk.id,
1093
1093
  choices: [],
1094
1094
  created: firstChunk.created,
@@ -1098,14 +1098,21 @@ function merge(chunks) {
1098
1098
  service_tier: firstChunk.service_tier,
1099
1099
  system_fingerprint: firstChunk.system_fingerprint
1100
1100
  });
1101
- result.choices?.forEach(choice => {
1101
+ }
1102
+
1103
+ function fixEmptyToolArguments(completion) {
1104
+ completion.choices?.forEach(choice => {
1102
1105
  choice.message.tool_calls?.filter(tc => tc.type === "function").forEach(toolCall => {
1103
1106
  if (toolCall.function.arguments === "") {
1104
1107
  toolCall.function.arguments = "{}";
1105
1108
  }
1106
1109
  });
1107
1110
  });
1108
- return result;
1111
+ return completion;
1112
+ }
1113
+
1114
+ function merge(chunks) {
1115
+ return fixEmptyToolArguments(mergeChunks(chunks));
1109
1116
  }
1110
1117
 
1111
1118
  function mergeChoice(acc, cur) {
@@ -1183,6 +1190,8 @@ const ChatGptCompletionMessageUtil = {
1183
1190
  transformCompletionChunk,
1184
1191
  accumulate,
1185
1192
  merge,
1193
+ mergeChunks,
1194
+ fixEmptyToolArguments,
1186
1195
  mergeChoice,
1187
1196
  mergeToolCalls
1188
1197
  };
@@ -1435,7 +1444,7 @@ async function reduceStreamingWithDispatch(stream, eventProcessor, abortSignal)
1435
1444
  };
1436
1445
  if (acc.object === "chat.completion.chunk") {
1437
1446
  registerContext([ acc, chunk ].flatMap(v => v.choices ?? []));
1438
- return ChatGptCompletionMessageUtil.merge([ acc, chunk ]);
1447
+ return ChatGptCompletionMessageUtil.mergeChunks([ acc, chunk ]);
1439
1448
  }
1440
1449
  registerContext(chunk.choices ?? []);
1441
1450
  return ChatGptCompletionMessageUtil.accumulate(acc, chunk);
@@ -1459,7 +1468,7 @@ async function reduceStreamingWithDispatch(stream, eventProcessor, abortSignal)
1459
1468
  });
1460
1469
  return completion;
1461
1470
  }
1462
- return nullableCompletion;
1471
+ return ChatGptCompletionMessageUtil.fixEmptyToolArguments(nullableCompletion);
1463
1472
  }
1464
1473
 
1465
1474
  function createOperationSelection(props) {
@@ -1998,14 +2007,38 @@ async function step$1(ctx, operations, retry, failures) {
1998
2007
  if (tc.type !== "function" || tc.function.name !== "cancelFunctions") {
1999
2008
  continue;
2000
2009
  }
2001
- const input = FUNCTION$2.parse(tc.function.arguments);
2002
- const validation = FUNCTION$2.validate(input);
2010
+ const parsed = FUNCTION$2.parse(tc.function.arguments);
2011
+ if (parsed.success === false) {
2012
+ failures.push({
2013
+ kind: "parse",
2014
+ id: tc.id,
2015
+ name: tc.function.name,
2016
+ failure: parsed
2017
+ });
2018
+ continue;
2019
+ }
2020
+ const validation = FUNCTION$2.validate(parsed.data);
2003
2021
  if (validation.success === false) {
2004
2022
  failures.push({
2023
+ kind: "validation",
2005
2024
  id: tc.id,
2006
2025
  name: tc.function.name,
2007
2026
  validation
2008
2027
  });
2028
+ continue;
2029
+ }
2030
+ const referenceErrors = validateFunctionExistence$1(ctx, validation.data);
2031
+ if (referenceErrors.length > 0) {
2032
+ failures.push({
2033
+ kind: "validation",
2034
+ id: tc.id,
2035
+ name: tc.function.name,
2036
+ validation: {
2037
+ success: false,
2038
+ data: validation.data,
2039
+ errors: referenceErrors
2040
+ }
2041
+ });
2009
2042
  }
2010
2043
  }
2011
2044
  }
@@ -2022,19 +2055,12 @@ async function step$1(ctx, operations, retry, failures) {
2022
2055
  } else if (tc.function.name !== "cancelFunctions") {
2023
2056
  continue;
2024
2057
  }
2025
- const input = (() => {
2026
- const _io0 = input => Array.isArray(input.functions) && input.functions.every(elem => "object" === typeof elem && null !== elem && _io1(elem));
2027
- const _io1 = input => "string" === typeof input.reason && "string" === typeof input.name;
2028
- const __is = input => "object" === typeof input && null !== input && _io0(input);
2029
- return input => {
2030
- input = JSON.parse(input);
2031
- return __is(input) ? input : null;
2032
- };
2033
- })()(tc.function.arguments);
2034
- if (input === null) {
2058
+ const parsed = FUNCTION$2.parse(tc.function.arguments);
2059
+ const validation = FUNCTION$2.validate(parsed.data);
2060
+ if (validation.success === false) {
2035
2061
  continue;
2036
2062
  }
2037
- for (const reference of input.functions) {
2063
+ for (const reference of validation.data.functions) {
2038
2064
  cancelFunctionFromContext(ctx, reference, assistant === undefined ? undefined : {
2039
2065
  assistant
2040
2066
  });
@@ -2052,19 +2078,46 @@ function emendMessages$1(failures) {
2052
2078
  id: f.id,
2053
2079
  function: {
2054
2080
  name: f.name,
2055
- arguments: JSON.stringify(f.validation.data)
2081
+ arguments: f.kind === "parse" ? f.failure.input : JSON.stringify(f.validation.data)
2056
2082
  }
2057
2083
  } ]
2058
2084
  }, {
2059
2085
  role: "tool",
2060
- content: JSON.stringify(f.validation.errors),
2061
- tool_call_id: f.id
2086
+ tool_call_id: f.id,
2087
+ content: f.kind === "parse" ? dedent`
2088
+ Invalid JSON format.
2089
+
2090
+ Here is the detailed parsing failure information,
2091
+ including error messages and their locations within the input:
2092
+
2093
+ \`\`\`json
2094
+ ${JSON.stringify(f.failure.errors)}
2095
+ \`\`\`
2096
+
2097
+ And here is the partially parsed data that was successfully
2098
+ extracted before the error occurred:
2099
+
2100
+ \`\`\`json
2101
+ ${JSON.stringify(f.failure.data)}
2102
+ \`\`\`
2103
+ ` : [ "🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.", "", "Each error below is computed absolute truth from rigorous type validation.", "You must fix ALL errors to achieve 100% schema compliance.", "", LlmJson.stringify(f.validation) ].join("\n")
2062
2104
  }, {
2063
2105
  role: "system",
2064
- content: [ "You A.I. assistant has composed wrong typed arguments.", "", "Correct it at the next function calling." ].join("\n")
2106
+ content: f.kind === "parse" ? AgenticaSystemPrompt.JSON_PARSE_ERROR.replace("${{FAILURE}}", JSON.stringify(f.failure)) : AgenticaSystemPrompt.VALIDATE
2065
2107
  } ]).flat();
2066
2108
  }
2067
2109
 
2110
+ function validateFunctionExistence$1(ctx, data) {
2111
+ const cancellable = ctx.stack.map(s => s.operation.name);
2112
+ const expected = cancellable.length === 0 ? "never" : cancellable.map(name => JSON.stringify(name)).join(" | ");
2113
+ return data.functions.flatMap((reference, i) => cancellable.includes(reference.name) ? [] : [ {
2114
+ path: `$input.functions[${i}].name`,
2115
+ expected,
2116
+ value: reference.name,
2117
+ description: cancellable.length === 0 ? `Function "${reference.name}" cannot be cancelled because no function is currently selected.` : `Function "${reference.name}" is not in the current selection, so it cannot be cancelled.`
2118
+ } ]);
2119
+ }
2120
+
2068
2121
  async function describe(ctx, histories) {
2069
2122
  if (histories.length === 0) {
2070
2123
  return;
@@ -2435,14 +2488,38 @@ async function step(ctx, operations, retry, failures) {
2435
2488
  if (tc.type !== "function" || tc.function.name !== "selectFunctions") {
2436
2489
  continue;
2437
2490
  }
2438
- const input = FUNCTION.parse(tc.function.arguments);
2439
- const validation = FUNCTION.validate(input);
2491
+ const parsed = FUNCTION.parse(tc.function.arguments);
2492
+ if (parsed.success === false) {
2493
+ failures.push({
2494
+ kind: "parse",
2495
+ id: tc.id,
2496
+ name: tc.function.name,
2497
+ failure: parsed
2498
+ });
2499
+ continue;
2500
+ }
2501
+ const validation = FUNCTION.validate(parsed.data);
2440
2502
  if (validation.success === false) {
2441
2503
  failures.push({
2504
+ kind: "validation",
2442
2505
  id: tc.id,
2443
2506
  name: tc.function.name,
2444
2507
  validation
2445
2508
  });
2509
+ continue;
2510
+ }
2511
+ const referenceErrors = validateFunctionExistence(ctx, operations, validation.data);
2512
+ if (referenceErrors.length > 0) {
2513
+ failures.push({
2514
+ kind: "validation",
2515
+ id: tc.id,
2516
+ name: tc.function.name,
2517
+ validation: {
2518
+ success: false,
2519
+ data: validation.data,
2520
+ errors: referenceErrors
2521
+ }
2522
+ });
2446
2523
  }
2447
2524
  }
2448
2525
  }
@@ -2459,19 +2536,12 @@ async function step(ctx, operations, retry, failures) {
2459
2536
  } else if (tc.function.name !== "selectFunctions") {
2460
2537
  continue;
2461
2538
  }
2462
- const input = (() => {
2463
- const _io0 = input => Array.isArray(input.functions) && input.functions.every(elem => "object" === typeof elem && null !== elem && _io1(elem));
2464
- const _io1 = input => "string" === typeof input.reason && "string" === typeof input.name;
2465
- const __is = input => "object" === typeof input && null !== input && _io0(input);
2466
- return input => {
2467
- input = JSON.parse(input);
2468
- return __is(input) ? input : null;
2469
- };
2470
- })()(tc.function.arguments);
2471
- if (input === null) {
2539
+ const parsed = FUNCTION.parse(tc.function.arguments);
2540
+ const validation = FUNCTION.validate(parsed.data);
2541
+ if (validation.success === false) {
2472
2542
  continue;
2473
2543
  }
2474
- for (const reference of input.functions) {
2544
+ for (const reference of validation.data.functions) {
2475
2545
  selectFunctionFromContext(ctx, reference, assistant === undefined ? undefined : {
2476
2546
  assistant
2477
2547
  });
@@ -2489,19 +2559,45 @@ function emendMessages(failures) {
2489
2559
  id: f.id,
2490
2560
  function: {
2491
2561
  name: f.name,
2492
- arguments: JSON.stringify(f.validation.data)
2562
+ arguments: f.kind === "parse" ? f.failure.input : JSON.stringify(f.validation.data)
2493
2563
  }
2494
2564
  } ]
2495
2565
  }, {
2496
2566
  role: "tool",
2497
- content: JSON.stringify(f.validation.errors),
2498
- tool_call_id: f.id
2567
+ tool_call_id: f.id,
2568
+ content: f.kind === "parse" ? dedent`
2569
+ Invalid JSON format.
2570
+
2571
+ Here is the detailed parsing failure information,
2572
+ including error messages and their locations within the input:
2573
+
2574
+ \`\`\`json
2575
+ ${JSON.stringify(f.failure.errors)}
2576
+ \`\`\`
2577
+
2578
+ And here is the partially parsed data that was successfully
2579
+ extracted before the error occurred:
2580
+
2581
+ \`\`\`json
2582
+ ${JSON.stringify(f.failure.data)}
2583
+ \`\`\`
2584
+ ` : [ "🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.", "", "Each error below is computed absolute truth from rigorous type validation.", "You must fix ALL errors to achieve 100% schema compliance.", "", LlmJson.stringify(f.validation) ].join("\n")
2499
2585
  }, {
2500
2586
  role: "system",
2501
- content: [ "You A.I. assistant has composed wrong typed arguments.", "", "Correct it at the next function calling." ].join("\n")
2587
+ content: f.kind === "parse" ? AgenticaSystemPrompt.JSON_PARSE_ERROR.replace("${{FAILURE}}", JSON.stringify(f.failure)) : AgenticaSystemPrompt.VALIDATE
2502
2588
  } ]).flat();
2503
2589
  }
2504
2590
 
2591
+ function validateFunctionExistence(ctx, candidates, data) {
2592
+ const expected = candidates.map(op => JSON.stringify(op.name)).join(" | ");
2593
+ return data.functions.flatMap((reference, i) => ctx.operations.flat.has(reference.name) ? [] : [ {
2594
+ path: `$input.functions[${i}].name`,
2595
+ expected,
2596
+ value: reference.name,
2597
+ description: [ `Function "${reference.name}" does not exist.`, "Select only from the functions provided by getApiFunctions()." ].join(" ")
2598
+ } ]);
2599
+ }
2600
+
2505
2601
  function execute(executor) {
2506
2602
  return async ctx => {
2507
2603
  if (ctx.ready() === false) {