@kenkaiiii/gg-agent 5.69.0 → 5.70.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.cjs
CHANGED
|
@@ -41,11 +41,11 @@ __export(index_exports, {
|
|
|
41
41
|
module.exports = __toCommonJS(index_exports);
|
|
42
42
|
|
|
43
43
|
// src/agent.ts
|
|
44
|
-
var
|
|
44
|
+
var import_gg_ai3 = require("@kenkaiiii/gg-ai");
|
|
45
45
|
|
|
46
46
|
// src/agent-loop.ts
|
|
47
47
|
var import_zod = require("zod");
|
|
48
|
-
var
|
|
48
|
+
var import_gg_ai2 = require("@kenkaiiii/gg-ai");
|
|
49
49
|
|
|
50
50
|
// src/local-backend.ts
|
|
51
51
|
function isLocalBackendUrl(baseUrl) {
|
|
@@ -69,6 +69,107 @@ function isLocalBackendUrl(baseUrl) {
|
|
|
69
69
|
return false;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// src/tool-call-hints.ts
|
|
73
|
+
var import_gg_ai = require("@kenkaiiii/gg-ai");
|
|
74
|
+
function normalizeName(name) {
|
|
75
|
+
return name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
76
|
+
}
|
|
77
|
+
function editDistance(a, b) {
|
|
78
|
+
let beforePrevious = [];
|
|
79
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
80
|
+
for (let i = 1; i <= a.length; i++) {
|
|
81
|
+
const current = [i];
|
|
82
|
+
for (let j = 1; j <= b.length; j++) {
|
|
83
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
84
|
+
let distance = Math.min(
|
|
85
|
+
(previous[j] ?? 0) + 1,
|
|
86
|
+
(current[j - 1] ?? 0) + 1,
|
|
87
|
+
(previous[j - 1] ?? 0) + cost
|
|
88
|
+
);
|
|
89
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
90
|
+
distance = Math.min(distance, (beforePrevious[j - 2] ?? 0) + 1);
|
|
91
|
+
}
|
|
92
|
+
current[j] = distance;
|
|
93
|
+
}
|
|
94
|
+
beforePrevious = previous;
|
|
95
|
+
previous = current;
|
|
96
|
+
}
|
|
97
|
+
return previous[b.length] ?? 0;
|
|
98
|
+
}
|
|
99
|
+
function closestName(name, candidates) {
|
|
100
|
+
const target = normalizeName(name);
|
|
101
|
+
if (!target) return void 0;
|
|
102
|
+
const limit = Math.min(3, Math.max(1, Math.floor(target.length / 3)));
|
|
103
|
+
let best;
|
|
104
|
+
for (const candidate of [...candidates].sort()) {
|
|
105
|
+
if (candidate === name) continue;
|
|
106
|
+
const distance = editDistance(target, normalizeName(candidate));
|
|
107
|
+
if (distance > limit) continue;
|
|
108
|
+
if (!best || distance < best.distance) best = { name: candidate, distance };
|
|
109
|
+
}
|
|
110
|
+
return best?.name;
|
|
111
|
+
}
|
|
112
|
+
function unknownToolMessage(name, available) {
|
|
113
|
+
const suggestion = closestName(name, available);
|
|
114
|
+
if (suggestion) return `Unknown tool: ${name}. Did you mean \`${suggestion}\`?`;
|
|
115
|
+
const names = [...available].sort();
|
|
116
|
+
const listed = names.length > 40 ? `${names.slice(0, 40).join(", ")}, \u2026` : names.join(", ");
|
|
117
|
+
const searchHint = available.includes("tool_search") ? " If the capability is not listed, call `tool_search` to load it." : "";
|
|
118
|
+
return `Unknown tool: ${name}. Available tools: ${listed}.${searchHint}`;
|
|
119
|
+
}
|
|
120
|
+
function isRecord(value) {
|
|
121
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
122
|
+
}
|
|
123
|
+
function typeLabel(node) {
|
|
124
|
+
if (!isRecord(node)) return "any";
|
|
125
|
+
if (Array.isArray(node.enum)) {
|
|
126
|
+
return node.enum.map((value) => JSON.stringify(value)).join(" | ");
|
|
127
|
+
}
|
|
128
|
+
const variants = node.anyOf ?? node.oneOf;
|
|
129
|
+
if (Array.isArray(variants)) {
|
|
130
|
+
return [...new Set(variants.map(typeLabel))].filter((t) => t !== "null").join(" | ") || "any";
|
|
131
|
+
}
|
|
132
|
+
if (node.type === "array") return `${typeLabel(node.items)}[]`;
|
|
133
|
+
if (Array.isArray(node.type)) {
|
|
134
|
+
return node.type.filter((t) => t !== "null").join(" | ") || "any";
|
|
135
|
+
}
|
|
136
|
+
return typeof node.type === "string" ? node.type : "any";
|
|
137
|
+
}
|
|
138
|
+
function objectShape(tool) {
|
|
139
|
+
let schema;
|
|
140
|
+
try {
|
|
141
|
+
schema = (0, import_gg_ai.resolveToolSchema)(tool);
|
|
142
|
+
} catch {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
if (!isRecord(schema) || !isRecord(schema.properties)) return void 0;
|
|
146
|
+
const required = new Set(
|
|
147
|
+
Array.isArray(schema.required) ? schema.required.filter((r) => typeof r === "string") : []
|
|
148
|
+
);
|
|
149
|
+
return { properties: schema.properties, required };
|
|
150
|
+
}
|
|
151
|
+
function argumentHints(tool, args) {
|
|
152
|
+
const shape = objectShape(tool);
|
|
153
|
+
if (!shape) return "";
|
|
154
|
+
const names = Object.keys(shape.properties);
|
|
155
|
+
if (names.length === 0) return `Expected arguments: none.`;
|
|
156
|
+
const fields = names.map((name) => {
|
|
157
|
+
const optional = shape.required.has(name) ? "" : "?";
|
|
158
|
+
return `${name}${optional}: ${typeLabel(shape.properties[name])}`;
|
|
159
|
+
});
|
|
160
|
+
const lines = [`Expected arguments: { ${fields.join(", ")} }`];
|
|
161
|
+
if (isRecord(args)) {
|
|
162
|
+
for (const key of Object.keys(args).sort()) {
|
|
163
|
+
if (key in shape.properties) continue;
|
|
164
|
+
const suggestion = closestName(key, names);
|
|
165
|
+
lines.push(
|
|
166
|
+
suggestion ? `Unknown field \`${key}\` \u2014 did you mean \`${suggestion}\`?` : `Unknown field \`${key}\` is not a parameter of this tool.`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return lines.join("\n");
|
|
171
|
+
}
|
|
172
|
+
|
|
72
173
|
// src/output-ceiling.ts
|
|
73
174
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
74
175
|
var MIN_PLAUSIBLE_CEILING = 256;
|
|
@@ -278,7 +379,7 @@ Partial output:` },
|
|
|
278
379
|
}
|
|
279
380
|
var _toolRedaction;
|
|
280
381
|
function toolRedactionOptions() {
|
|
281
|
-
_toolRedaction ??= { secrets: (0,
|
|
382
|
+
_toolRedaction ??= { secrets: (0, import_gg_ai2.environmentSecrets)(process.env) };
|
|
282
383
|
return _toolRedaction;
|
|
283
384
|
}
|
|
284
385
|
var _diagFn = null;
|
|
@@ -361,7 +462,7 @@ function isBillingError(err) {
|
|
|
361
462
|
if (!(err instanceof Error)) return false;
|
|
362
463
|
const statusCode = err.statusCode;
|
|
363
464
|
if (statusCode === 402) return true;
|
|
364
|
-
return (0,
|
|
465
|
+
return (0, import_gg_ai2.isHardBillingMessage)(err.message);
|
|
365
466
|
}
|
|
366
467
|
function isUsageLimitError(err) {
|
|
367
468
|
if (!(err instanceof Error)) return false;
|
|
@@ -730,7 +831,7 @@ async function* agentLoop(messages, options) {
|
|
|
730
831
|
});
|
|
731
832
|
}
|
|
732
833
|
}
|
|
733
|
-
const result = (0,
|
|
834
|
+
const result = (0, import_gg_ai2.stream)({
|
|
734
835
|
provider: options.provider,
|
|
735
836
|
model: options.model,
|
|
736
837
|
messages,
|
|
@@ -1193,7 +1294,7 @@ async function* agentLoop(messages, options) {
|
|
|
1193
1294
|
});
|
|
1194
1295
|
yield {
|
|
1195
1296
|
type: "error",
|
|
1196
|
-
error: new
|
|
1297
|
+
error: new import_gg_ai2.GGAIError(
|
|
1197
1298
|
`The connection to the API provider stopped responding after ${MAX_STALL_RETRIES} automatic retries. Your conversation is preserved.`,
|
|
1198
1299
|
{
|
|
1199
1300
|
source: "network",
|
|
@@ -1607,7 +1708,7 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1607
1708
|
options.seenToolCalls.add(signature);
|
|
1608
1709
|
}
|
|
1609
1710
|
if (!tool) {
|
|
1610
|
-
resultContent =
|
|
1711
|
+
resultContent = unknownToolMessage(toolCall.name, [...options.toolMap.keys()]);
|
|
1611
1712
|
isError = true;
|
|
1612
1713
|
} else {
|
|
1613
1714
|
try {
|
|
@@ -1641,8 +1742,8 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1641
1742
|
};
|
|
1642
1743
|
const raw = await tool.execute(parsed, ctx);
|
|
1643
1744
|
const normalized = normalizeToolResult(raw);
|
|
1644
|
-
resultContent = (0,
|
|
1645
|
-
details = (0,
|
|
1745
|
+
resultContent = (0, import_gg_ai2.redactValue)(normalized.content, toolRedactionOptions());
|
|
1746
|
+
details = (0, import_gg_ai2.redactValue)(normalized.details, toolRedactionOptions());
|
|
1646
1747
|
if (options.transformToolResult) {
|
|
1647
1748
|
try {
|
|
1648
1749
|
resultContent = options.transformToolResult(
|
|
@@ -1663,12 +1764,14 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1663
1764
|
const failureCount = (options.invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;
|
|
1664
1765
|
options.invalidToolArgumentCounts.set(failureKey, failureCount);
|
|
1665
1766
|
invalidArgAttempt = failureCount;
|
|
1767
|
+
const hints = argumentHints(tool, toolCall.args);
|
|
1666
1768
|
resultContent = `Invalid arguments for tool \`${toolCall.name}\`:
|
|
1667
|
-
` + prettyError +
|
|
1769
|
+
` + prettyError + (hints ? `
|
|
1770
|
+
${hints}` : "") + "\nRe-issue the call with each field as the correct type.";
|
|
1668
1771
|
if (failureCount >= 3) {
|
|
1669
1772
|
const recoverable = Object.keys(toolCall.args ?? {}).length === 0;
|
|
1670
1773
|
options.markFatalToolArgumentError(
|
|
1671
|
-
new
|
|
1774
|
+
new import_gg_ai2.GGAIError(
|
|
1672
1775
|
`The model repeatedly issued invalid arguments for tool \`${toolCall.name}\`. This is usually an upstream model/tool-calling bug` + (recoverable ? " (the provider's stream returned empty tool-call arguments)" : "") + `. Your conversation is preserved; send another message or switch models to continue.`,
|
|
1673
1776
|
{
|
|
1674
1777
|
source: "provider",
|
|
@@ -1680,15 +1783,15 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
|
|
|
1680
1783
|
);
|
|
1681
1784
|
}
|
|
1682
1785
|
} else {
|
|
1683
|
-
resultContent = (0,
|
|
1786
|
+
resultContent = (0, import_gg_ai2.redactValue)(
|
|
1684
1787
|
err instanceof Error ? err.message : String(err),
|
|
1685
1788
|
toolRedactionOptions()
|
|
1686
1789
|
);
|
|
1687
1790
|
}
|
|
1688
1791
|
}
|
|
1689
1792
|
}
|
|
1690
|
-
resultContent = (0,
|
|
1691
|
-
details = (0,
|
|
1793
|
+
resultContent = (0, import_gg_ai2.redactValue)(resultContent, toolRedactionOptions());
|
|
1794
|
+
details = (0, import_gg_ai2.redactValue)(details, toolRedactionOptions());
|
|
1692
1795
|
if (options.preemptSignal?.aborted && isInterruptibleTool(options.toolMap.get(toolCall.name), toolCall.name)) {
|
|
1693
1796
|
const marked = markSteerInterrupted({
|
|
1694
1797
|
toolCallId: toolCall.id,
|
|
@@ -1764,7 +1867,7 @@ function createPreemptTracker(options, eventStream, state, resultsById, dispatch
|
|
|
1764
1867
|
};
|
|
1765
1868
|
}
|
|
1766
1869
|
async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
|
|
1767
|
-
const eventStream = new
|
|
1870
|
+
const eventStream = new import_gg_ai2.EventStream();
|
|
1768
1871
|
const state = { finalized: false };
|
|
1769
1872
|
const resultsById = /* @__PURE__ */ new Map();
|
|
1770
1873
|
const dispatchedIds = /* @__PURE__ */ new Set();
|
|
@@ -1832,7 +1935,7 @@ async function* executeToolCallsMixed(toolCalls, initialToolResults, options) {
|
|
|
1832
1935
|
return { toolResults, aborted, preempted: !aborted && tracker.preempted() };
|
|
1833
1936
|
}
|
|
1834
1937
|
async function* executeToolCallsParallel(toolCalls, initialToolResults, options) {
|
|
1835
|
-
const eventStream = new
|
|
1938
|
+
const eventStream = new import_gg_ai2.EventStream();
|
|
1836
1939
|
const state = { finalized: false };
|
|
1837
1940
|
const resultsById = /* @__PURE__ */ new Map();
|
|
1838
1941
|
const dispatchedIds = /* @__PURE__ */ new Set();
|
|
@@ -1903,8 +2006,8 @@ function capToolResults(toolResults, maxToolResultChars) {
|
|
|
1903
2006
|
const originalChars = toolResult.content.length;
|
|
1904
2007
|
const headChars = Math.floor(max * 0.7);
|
|
1905
2008
|
const tailChars = max - headChars;
|
|
1906
|
-
const head = (0,
|
|
1907
|
-
const tail = (0,
|
|
2009
|
+
const head = (0, import_gg_ai2.sliceHead)(toolResult.content, headChars);
|
|
2010
|
+
const tail = (0, import_gg_ai2.sliceTail)(toolResult.content, tailChars);
|
|
1908
2011
|
const omitted = originalChars - head.length - tail.length;
|
|
1909
2012
|
toolResult.content = head + `
|
|
1910
2013
|
|
|
@@ -1940,11 +2043,11 @@ function capTurnToolResults(toolResults, maxTurnToolResultChars) {
|
|
|
1940
2043
|
const headChars = Math.floor(fairShare * 0.7);
|
|
1941
2044
|
const tailChars = fairShare - headChars;
|
|
1942
2045
|
const omitted = originalChars - fairShare;
|
|
1943
|
-
toolResult.content = (0,
|
|
2046
|
+
toolResult.content = (0, import_gg_ai2.sliceHead)(toolResult.content, headChars) + `
|
|
1944
2047
|
|
|
1945
2048
|
[... ${omitted} characters trimmed: this turn's combined tool results exceeded the per-turn budget. Re-run this call alone with narrower filters or offset/limit if you need the omitted content ...]
|
|
1946
2049
|
|
|
1947
|
-
` + (0,
|
|
2050
|
+
` + (0, import_gg_ai2.sliceTail)(toolResult.content, tailChars);
|
|
1948
2051
|
toolResult.capped = {
|
|
1949
2052
|
originalChars: toolResult.capped?.originalChars ?? originalChars,
|
|
1950
2053
|
keptChars: toolResult.content.length,
|
|
@@ -1963,8 +2066,8 @@ function truncateToolResultText(text, maxChars) {
|
|
|
1963
2066
|
if (text.length <= maxChars) return text;
|
|
1964
2067
|
const tailChars = Math.min(Math.floor(maxChars * 0.3), 2e4);
|
|
1965
2068
|
const headChars = Math.max(maxChars - tailChars, 0);
|
|
1966
|
-
const head = (0,
|
|
1967
|
-
const tail = (0,
|
|
2069
|
+
const head = (0, import_gg_ai2.sliceHead)(text, headChars);
|
|
2070
|
+
const tail = (0, import_gg_ai2.sliceTail)(text, tailChars);
|
|
1968
2071
|
const omitted = text.length - head.length - tail.length;
|
|
1969
2072
|
return `${head}
|
|
1970
2073
|
|
|
@@ -2113,7 +2216,7 @@ var AgentStream = class {
|
|
|
2113
2216
|
rejectResult;
|
|
2114
2217
|
hasConsumer = false;
|
|
2115
2218
|
constructor(generator, onDone) {
|
|
2116
|
-
this.events = new
|
|
2219
|
+
this.events = new import_gg_ai3.EventStream();
|
|
2117
2220
|
this.resultPromise = new Promise((resolve, reject) => {
|
|
2118
2221
|
this.resolveResult = resolve;
|
|
2119
2222
|
this.rejectResult = reject;
|