@agentica/core 0.36.2 → 0.36.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/lib/index.mjs CHANGED
@@ -6,7 +6,7 @@ import { v4 } from "uuid";
6
6
 
7
7
  import { HttpLlm, OpenApi, McpLlm } from "@samchon/openapi";
8
8
 
9
- import { removeTrailingCommas, addMissingBraces, removeEmptyObjectPrefix } from "es-jsonkit";
9
+ import { jsonrepair } from "jsonrepair";
10
10
 
11
11
  import { Escaper } from "typia/lib/utils/Escaper";
12
12
 
@@ -911,14 +911,162 @@ const ChatGptTokenUsageAggregator = {
911
911
  };
912
912
 
913
913
  const JsonUtil = {
914
- parse
914
+ parse,
915
+ stringifyValidateFailure
915
916
  };
916
917
 
917
- const pipe = (...fns) => str => fns.reduce(((acc, fn) => fn(acc)), str);
918
-
919
918
  function parse(str) {
920
- const corrected = pipe(removeEmptyObjectPrefix, addMissingBraces, removeTrailingCommas)(str);
921
- return JSON.parse(corrected);
919
+ str = jsonrepair(str);
920
+ return JSON.parse(str);
921
+ }
922
+
923
+ function stringifyValidateFailure(failure) {
924
+ return stringify({
925
+ value: failure.data,
926
+ errors: failure.errors,
927
+ path: "$input",
928
+ tab: 0,
929
+ inArray: false,
930
+ inToJson: false
931
+ });
932
+ }
933
+
934
+ function stringify(props) {
935
+ const {value, errors, path, tab, inArray, inToJson} = props;
936
+ const indent = " ".repeat(tab);
937
+ const errorComment = getErrorComment(path, errors);
938
+ if (inArray && value === undefined) {
939
+ return `${indent}undefined${errorComment}`;
940
+ }
941
+ if (Array.isArray(value)) {
942
+ if (value.length === 0) {
943
+ return `${indent}[]${errorComment}`;
944
+ }
945
+ const lines = [];
946
+ lines.push(`${indent}[${errorComment}`);
947
+ value.forEach(((item, index) => {
948
+ const itemPath = `${path}[${index}]`;
949
+ let itemStr = stringify({
950
+ value: item,
951
+ errors,
952
+ path: itemPath,
953
+ tab: tab + 1,
954
+ inArray: true,
955
+ inToJson: false
956
+ });
957
+ if (index < value.length - 1) {
958
+ const itemLines = itemStr.split("\n");
959
+ const lastLine = itemLines[itemLines.length - 1];
960
+ const commentIndex = lastLine.indexOf(" //");
961
+ if (commentIndex !== -1) {
962
+ itemLines[itemLines.length - 1] = `${lastLine.slice(0, commentIndex)},${lastLine.slice(commentIndex)}`;
963
+ } else {
964
+ itemLines[itemLines.length - 1] += ",";
965
+ }
966
+ itemStr = itemLines.join("\n");
967
+ }
968
+ lines.push(itemStr);
969
+ }));
970
+ lines.push(`${indent}]`);
971
+ return lines.join("\n");
972
+ }
973
+ if (typeof value === "object" && value !== null) {
974
+ if (!inToJson && typeof value.toJSON === "function") {
975
+ const jsonValue = value.toJSON();
976
+ return stringify({
977
+ value: jsonValue,
978
+ errors,
979
+ path,
980
+ tab,
981
+ inArray,
982
+ inToJson: true
983
+ });
984
+ }
985
+ const existingEntries = Object.entries(value).filter((([_, val]) => val !== undefined));
986
+ const missingKeys = getMissingProperties(path, value, errors);
987
+ const allKeys = [ ...existingEntries.map((([key]) => key)), ...missingKeys ];
988
+ if (allKeys.length === 0) {
989
+ return `${indent}{}${errorComment}`;
990
+ }
991
+ const lines = [];
992
+ lines.push(`${indent}{${errorComment}`);
993
+ allKeys.forEach(((key, index, array) => {
994
+ const propPath = Escaper.variable(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
995
+ const propIndent = " ".repeat(tab + 1);
996
+ const val = missingKeys.includes(key) ? undefined : value[key];
997
+ if (val === undefined || val === null || typeof val === "boolean" || typeof val === "number" || typeof val === "string") {
998
+ const propErrorComment = getErrorComment(propPath, errors);
999
+ const valueStr = val === undefined ? `${propIndent}"${key}": undefined` : `${propIndent}"${key}": ${JSON.stringify(val)}`;
1000
+ const withComma = index < array.length - 1 ? `${valueStr},` : valueStr;
1001
+ const line = withComma + propErrorComment;
1002
+ lines.push(line);
1003
+ } else {
1004
+ const keyLine = `${propIndent}"${key}": `;
1005
+ let valStr = stringify({
1006
+ value: val,
1007
+ errors,
1008
+ path: propPath,
1009
+ tab: tab + 1,
1010
+ inArray: false,
1011
+ inToJson: false
1012
+ });
1013
+ const valStrWithoutIndent = valStr.trimStart();
1014
+ if (index < array.length - 1) {
1015
+ const valLines = valStrWithoutIndent.split("\n");
1016
+ const lastLine = valLines[valLines.length - 1];
1017
+ const commentIndex = lastLine.indexOf(" //");
1018
+ if (commentIndex !== -1) {
1019
+ valLines[valLines.length - 1] = `${lastLine.slice(0, commentIndex)},${lastLine.slice(commentIndex)}`;
1020
+ } else {
1021
+ valLines[valLines.length - 1] += ",";
1022
+ }
1023
+ valStr = valLines.join("\n");
1024
+ } else {
1025
+ valStr = valStrWithoutIndent;
1026
+ }
1027
+ const combined = keyLine + valStr;
1028
+ lines.push(combined);
1029
+ }
1030
+ }));
1031
+ lines.push(`${indent}}`);
1032
+ return lines.join("\n");
1033
+ }
1034
+ const valStr = value === undefined ? "undefined" : JSON.stringify(value) ?? String(value);
1035
+ return `${indent}${valStr}${errorComment}`;
1036
+ }
1037
+
1038
+ function getErrorComment(path, errors) {
1039
+ const pathErrors = errors.filter((e => e.path === path));
1040
+ if (pathErrors.length === 0) {
1041
+ return "";
1042
+ }
1043
+ return ` // ❌ ${JSON.stringify(pathErrors.map((e => ({
1044
+ path: e.path,
1045
+ expected: e.expected,
1046
+ description: e.description
1047
+ }))))}`;
1048
+ }
1049
+
1050
+ function getMissingProperties(path, value, errors) {
1051
+ const missingKeys = new Set;
1052
+ for (const e of errors) {
1053
+ const childKey = extractDirectChildKey(path, e.path);
1054
+ if (childKey !== null) {
1055
+ if (!(childKey in value)) {
1056
+ missingKeys.add(childKey);
1057
+ }
1058
+ }
1059
+ }
1060
+ return Array.from(missingKeys);
1061
+ }
1062
+
1063
+ function extractDirectChildKey(parentPath, errorPath) {
1064
+ if (!errorPath.startsWith(parentPath)) {
1065
+ return null;
1066
+ }
1067
+ const suffix = errorPath.slice(parentPath.length);
1068
+ const match = suffix.match(/^\.([^.[\]]+)$/);
1069
+ return match !== null ? match[1] : null;
922
1070
  }
923
1071
 
924
1072
  function transformCompletionChunk(source) {
@@ -1344,155 +1492,6 @@ async function reduceStreamingWithDispatch(stream, eventProcessor, abortSignal)
1344
1492
  return nullableCompletion;
1345
1493
  }
1346
1494
 
1347
- function stringifyValidateFailure(failure) {
1348
- return stringify({
1349
- value: failure.data,
1350
- errors: failure.errors,
1351
- path: "$input",
1352
- tab: 0,
1353
- inArray: false,
1354
- inToJson: false
1355
- });
1356
- }
1357
-
1358
- function stringify(props) {
1359
- const {value, errors, path, tab, inArray, inToJson} = props;
1360
- const indent = " ".repeat(tab);
1361
- const errorComment = getErrorComment(path, errors);
1362
- if (inArray && value === undefined) {
1363
- return `${indent}undefined${errorComment}`;
1364
- }
1365
- if (Array.isArray(value)) {
1366
- if (value.length === 0) {
1367
- return `${indent}[]${errorComment}`;
1368
- }
1369
- const lines = [];
1370
- lines.push(`${indent}[${errorComment}`);
1371
- value.forEach(((item, index) => {
1372
- const itemPath = `${path}[${index}]`;
1373
- let itemStr = stringify({
1374
- value: item,
1375
- errors,
1376
- path: itemPath,
1377
- tab: tab + 1,
1378
- inArray: true,
1379
- inToJson: false
1380
- });
1381
- if (index < value.length - 1) {
1382
- const itemLines = itemStr.split("\n");
1383
- const lastLine = itemLines[itemLines.length - 1];
1384
- const commentIndex = lastLine.indexOf(" //");
1385
- if (commentIndex !== -1) {
1386
- itemLines[itemLines.length - 1] = `${lastLine.slice(0, commentIndex)},${lastLine.slice(commentIndex)}`;
1387
- } else {
1388
- itemLines[itemLines.length - 1] += ",";
1389
- }
1390
- itemStr = itemLines.join("\n");
1391
- }
1392
- lines.push(itemStr);
1393
- }));
1394
- lines.push(`${indent}]`);
1395
- return lines.join("\n");
1396
- }
1397
- if (typeof value === "object" && value !== null) {
1398
- if (!inToJson && typeof value.toJSON === "function") {
1399
- const jsonValue = value.toJSON();
1400
- return stringify({
1401
- value: jsonValue,
1402
- errors,
1403
- path,
1404
- tab,
1405
- inArray,
1406
- inToJson: true
1407
- });
1408
- }
1409
- const existingEntries = Object.entries(value).filter((([_, val]) => val !== undefined));
1410
- const missingKeys = getMissingProperties(path, value, errors);
1411
- const allKeys = [ ...existingEntries.map((([key]) => key)), ...missingKeys ];
1412
- if (allKeys.length === 0) {
1413
- return `${indent}{}${errorComment}`;
1414
- }
1415
- const lines = [];
1416
- lines.push(`${indent}{${errorComment}`);
1417
- allKeys.forEach(((key, index, array) => {
1418
- const propPath = Escaper.variable(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
1419
- const propIndent = " ".repeat(tab + 1);
1420
- const val = missingKeys.includes(key) ? undefined : value[key];
1421
- if (val === undefined || val === null || typeof val === "boolean" || typeof val === "number" || typeof val === "string") {
1422
- const propErrorComment = getErrorComment(propPath, errors);
1423
- const valueStr = val === undefined ? `${propIndent}"${key}": undefined` : `${propIndent}"${key}": ${JSON.stringify(val)}`;
1424
- const withComma = index < array.length - 1 ? `${valueStr},` : valueStr;
1425
- const line = withComma + propErrorComment;
1426
- lines.push(line);
1427
- } else {
1428
- const keyLine = `${propIndent}"${key}": `;
1429
- let valStr = stringify({
1430
- value: val,
1431
- errors,
1432
- path: propPath,
1433
- tab: tab + 1,
1434
- inArray: false,
1435
- inToJson: false
1436
- });
1437
- const valStrWithoutIndent = valStr.trimStart();
1438
- if (index < array.length - 1) {
1439
- const valLines = valStrWithoutIndent.split("\n");
1440
- const lastLine = valLines[valLines.length - 1];
1441
- const commentIndex = lastLine.indexOf(" //");
1442
- if (commentIndex !== -1) {
1443
- valLines[valLines.length - 1] = `${lastLine.slice(0, commentIndex)},${lastLine.slice(commentIndex)}`;
1444
- } else {
1445
- valLines[valLines.length - 1] += ",";
1446
- }
1447
- valStr = valLines.join("\n");
1448
- } else {
1449
- valStr = valStrWithoutIndent;
1450
- }
1451
- const combined = keyLine + valStr;
1452
- lines.push(combined);
1453
- }
1454
- }));
1455
- lines.push(`${indent}}`);
1456
- return lines.join("\n");
1457
- }
1458
- const valStr = value === undefined ? "undefined" : JSON.stringify(value) ?? String(value);
1459
- return `${indent}${valStr}${errorComment}`;
1460
- }
1461
-
1462
- function getErrorComment(path, errors) {
1463
- const pathErrors = errors.filter((e => e.path === path));
1464
- if (pathErrors.length === 0) {
1465
- return "";
1466
- }
1467
- return ` // ❌ ${JSON.stringify(pathErrors.map((e => ({
1468
- path: e.path,
1469
- expected: e.expected,
1470
- description: e.description
1471
- }))))}`;
1472
- }
1473
-
1474
- function getMissingProperties(path, value, errors) {
1475
- const missingKeys = new Set;
1476
- for (const e of errors) {
1477
- const childKey = extractDirectChildKey(path, e.path);
1478
- if (childKey !== null) {
1479
- if (!(childKey in value)) {
1480
- missingKeys.add(childKey);
1481
- }
1482
- }
1483
- }
1484
- return Array.from(missingKeys);
1485
- }
1486
-
1487
- function extractDirectChildKey(parentPath, errorPath) {
1488
- if (!errorPath.startsWith(parentPath)) {
1489
- return null;
1490
- }
1491
- const suffix = errorPath.slice(parentPath.length);
1492
- const match = suffix.match(/^\.([^.[\]]+)$/);
1493
- return match !== null ? match[1] : null;
1494
- }
1495
-
1496
1495
  function createOperationSelection(props) {
1497
1496
  return {
1498
1497
  operation: props.operation,
@@ -1644,9 +1643,9 @@ async function correctTypeError(ctx, callEvent, validateEvent, previousValidatio
1644
1643
  toolCall: {
1645
1644
  id: callEvent.id,
1646
1645
  arguments: JSON.stringify(callEvent.arguments),
1647
- result: [ "🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.", "", "The validation errors below represent computed absolute truth from rigorous type validation.", "Each error is marked with ❌ comments showing the exact location, expected type, and actual value.", "", "You must fix ALL errors to achieve 100% schema compliance.", "", "```json", stringifyValidateFailure(validateEvent.result), "```" ].join("\n")
1646
+ result: [ "🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.", "", "The validation errors below represent computed absolute truth from rigorous type validation.", "Each error is marked with ❌ comments showing the exact location, expected type, and actual value.", "", "You must fix ALL errors to achieve 100% schema compliance.", "", "```json", JsonUtil.stringifyValidateFailure(validateEvent.result), "```" ].join("\n")
1648
1647
  },
1649
- systemPrompt: ctx.config?.systemPrompt?.validate?.(previousValidationErrors.slice(0, -1)) ?? [ AgenticaSystemPrompt.VALIDATE, ...previousValidationErrors.length > 1 ? [ "", AgenticaSystemPrompt.VALIDATE_REPEATED.replace("${{HISTORICAL_ERRORS}}", previousValidationErrors.slice(0, -1).map(((ve, i) => [ `### ${i + 1}. Previous Validation Error`, "", "```json", stringifyValidateFailure(ve.result), "```" ].join("\n"))).join("\n\n")) ] : [] ].join("\n"),
1648
+ systemPrompt: ctx.config?.systemPrompt?.validate?.(previousValidationErrors.slice(0, -1)) ?? [ AgenticaSystemPrompt.VALIDATE, ...previousValidationErrors.length > 1 ? [ "", AgenticaSystemPrompt.VALIDATE_REPEATED.replace("${{HISTORICAL_ERRORS}}", previousValidationErrors.slice(0, -1).map(((ve, i) => [ `### ${i + 1}. Previous Validation Error`, "", "```json", JsonUtil.stringifyValidateFailure(ve.result), "```" ].join("\n"))).join("\n\n")) ] : [] ].join("\n"),
1650
1649
  life,
1651
1650
  previousValidationErrors
1652
1651
  });