@kenkaiiii/gg-agent 5.69.0 → 5.71.0
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 +126 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +105 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -36,6 +36,107 @@ function isLocalBackendUrl(baseUrl) {
|
|
|
36
36
|
return false;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// src/tool-call-hints.ts
|
|
40
|
+
import { resolveToolSchema } from "@kenkaiiii/gg-ai";
|
|
41
|
+
function normalizeName(name) {
|
|
42
|
+
return name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
43
|
+
}
|
|
44
|
+
function editDistance(a, b) {
|
|
45
|
+
let beforePrevious = [];
|
|
46
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
47
|
+
for (let i = 1; i <= a.length; i++) {
|
|
48
|
+
const current = [i];
|
|
49
|
+
for (let j = 1; j <= b.length; j++) {
|
|
50
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
51
|
+
let distance = Math.min(
|
|
52
|
+
(previous[j] ?? 0) + 1,
|
|
53
|
+
(current[j - 1] ?? 0) + 1,
|
|
54
|
+
(previous[j - 1] ?? 0) + cost
|
|
55
|
+
);
|
|
56
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
57
|
+
distance = Math.min(distance, (beforePrevious[j - 2] ?? 0) + 1);
|
|
58
|
+
}
|
|
59
|
+
current[j] = distance;
|
|
60
|
+
}
|
|
61
|
+
beforePrevious = previous;
|
|
62
|
+
previous = current;
|
|
63
|
+
}
|
|
64
|
+
return previous[b.length] ?? 0;
|
|
65
|
+
}
|
|
66
|
+
function closestName(name, candidates) {
|
|
67
|
+
const target = normalizeName(name);
|
|
68
|
+
if (!target) return void 0;
|
|
69
|
+
const limit = Math.min(3, Math.max(1, Math.floor(target.length / 3)));
|
|
70
|
+
let best;
|
|
71
|
+
for (const candidate of [...candidates].sort()) {
|
|
72
|
+
if (candidate === name) continue;
|
|
73
|
+
const distance = editDistance(target, normalizeName(candidate));
|
|
74
|
+
if (distance > limit) continue;
|
|
75
|
+
if (!best || distance < best.distance) best = { name: candidate, distance };
|
|
76
|
+
}
|
|
77
|
+
return best?.name;
|
|
78
|
+
}
|
|
79
|
+
function unknownToolMessage(name, available) {
|
|
80
|
+
const suggestion = closestName(name, available);
|
|
81
|
+
if (suggestion) return `Unknown tool: ${name}. Did you mean \`${suggestion}\`?`;
|
|
82
|
+
const names = [...available].sort();
|
|
83
|
+
const listed = names.length > 40 ? `${names.slice(0, 40).join(", ")}, \u2026` : names.join(", ");
|
|
84
|
+
const searchHint = available.includes("tool_search") ? " If the capability is not listed, call `tool_search` to load it." : "";
|
|
85
|
+
return `Unknown tool: ${name}. Available tools: ${listed}.${searchHint}`;
|
|
86
|
+
}
|
|
87
|
+
function isRecord(value) {
|
|
88
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
89
|
+
}
|
|
90
|
+
function typeLabel(node) {
|
|
91
|
+
if (!isRecord(node)) return "any";
|
|
92
|
+
if (Array.isArray(node.enum)) {
|
|
93
|
+
return node.enum.map((value) => JSON.stringify(value)).join(" | ");
|
|
94
|
+
}
|
|
95
|
+
const variants = node.anyOf ?? node.oneOf;
|
|
96
|
+
if (Array.isArray(variants)) {
|
|
97
|
+
return [...new Set(variants.map(typeLabel))].filter((t) => t !== "null").join(" | ") || "any";
|
|
98
|
+
}
|
|
99
|
+
if (node.type === "array") return `${typeLabel(node.items)}[]`;
|
|
100
|
+
if (Array.isArray(node.type)) {
|
|
101
|
+
return node.type.filter((t) => t !== "null").join(" | ") || "any";
|
|
102
|
+
}
|
|
103
|
+
return typeof node.type === "string" ? node.type : "any";
|
|
104
|
+
}
|
|
105
|
+
function objectShape(tool) {
|
|
106
|
+
let schema;
|
|
107
|
+
try {
|
|
108
|
+
schema = resolveToolSchema(tool);
|
|
109
|
+
} catch {
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
if (!isRecord(schema) || !isRecord(schema.properties)) return void 0;
|
|
113
|
+
const required = new Set(
|
|
114
|
+
Array.isArray(schema.required) ? schema.required.filter((r) => typeof r === "string") : []
|
|
115
|
+
);
|
|
116
|
+
return { properties: schema.properties, required };
|
|
117
|
+
}
|
|
118
|
+
function argumentHints(tool, args) {
|
|
119
|
+
const shape = objectShape(tool);
|
|
120
|
+
if (!shape) return "";
|
|
121
|
+
const names = Object.keys(shape.properties);
|
|
122
|
+
if (names.length === 0) return `Expected arguments: none.`;
|
|
123
|
+
const fields = names.map((name) => {
|
|
124
|
+
const optional = shape.required.has(name) ? "" : "?";
|
|
125
|
+
return `${name}${optional}: ${typeLabel(shape.properties[name])}`;
|
|
126
|
+
});
|
|
127
|
+
const lines = [`Expected arguments: { ${fields.join(", ")} }`];
|
|
128
|
+
if (isRecord(args)) {
|
|
129
|
+
for (const key of Object.keys(args).sort()) {
|
|
130
|
+
if (key in shape.properties) continue;
|
|
131
|
+
const suggestion = closestName(key, names);
|
|
132
|
+
lines.push(
|
|
133
|
+
suggestion ? `Unknown field \`${key}\` \u2014 did you mean \`${suggestion}\`?` : `Unknown field \`${key}\` is not a parameter of this tool.`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
|
|
39
140
|
// src/output-ceiling.ts
|
|
40
141
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
41
142
|
var MIN_PLAUSIBLE_CEILING = 256;
|
|
@@ -1574,7 +1675,7 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1574
1675
|
options.seenToolCalls.add(signature);
|
|
1575
1676
|
}
|
|
1576
1677
|
if (!tool) {
|
|
1577
|
-
resultContent =
|
|
1678
|
+
resultContent = unknownToolMessage(toolCall.name, [...options.toolMap.keys()]);
|
|
1578
1679
|
isError = true;
|
|
1579
1680
|
} else {
|
|
1580
1681
|
try {
|
|
@@ -1630,8 +1731,10 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1630
1731
|
const failureCount = (options.invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;
|
|
1631
1732
|
options.invalidToolArgumentCounts.set(failureKey, failureCount);
|
|
1632
1733
|
invalidArgAttempt = failureCount;
|
|
1734
|
+
const hints = argumentHints(tool, toolCall.args);
|
|
1633
1735
|
resultContent = `Invalid arguments for tool \`${toolCall.name}\`:
|
|
1634
|
-
` + prettyError +
|
|
1736
|
+
` + prettyError + (hints ? `
|
|
1737
|
+
${hints}` : "") + "\nRe-issue the call with each field as the correct type.";
|
|
1635
1738
|
if (failureCount >= 3) {
|
|
1636
1739
|
const recoverable = Object.keys(toolCall.args ?? {}).length === 0;
|
|
1637
1740
|
options.markFatalToolArgumentError(
|