@blockrun/franklin 3.15.0 → 3.15.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.
|
@@ -3,6 +3,7 @@ export declare function normalizeSearchQuery(query: string): {
|
|
|
3
3
|
normalized: string;
|
|
4
4
|
tokens: string[];
|
|
5
5
|
};
|
|
6
|
+
export declare function isToolClassFailure(name: string, result: CapabilityResult): boolean;
|
|
6
7
|
export declare class SessionToolGuard {
|
|
7
8
|
private turn;
|
|
8
9
|
private webSearchesThisTurn;
|
package/dist/agent/tool-guard.js
CHANGED
|
@@ -128,6 +128,35 @@ function readKey(resolved, offset, limit) {
|
|
|
128
128
|
function fetchKey(url, maxLength) {
|
|
129
129
|
return `${url}::${maxLength ?? 12288}`;
|
|
130
130
|
}
|
|
131
|
+
// Circuit-breaker classifier for the per-tool kill switch.
|
|
132
|
+
//
|
|
133
|
+
// `isError: true` covers everything from "tool itself broke" (network, parse,
|
|
134
|
+
// timeout) to "agent fed me a bad input" (404 on a guessed URL, malformed URL).
|
|
135
|
+
// Only the first category should count toward disabling the tool — otherwise
|
|
136
|
+
// three hallucinated URLs in one prompt permanently kill WebFetch for the
|
|
137
|
+
// session, even though the tool worked correctly each time.
|
|
138
|
+
export function isToolClassFailure(name, result) {
|
|
139
|
+
if (!result.isError)
|
|
140
|
+
return false;
|
|
141
|
+
const out = String(result.output ?? '');
|
|
142
|
+
if (name === 'WebFetch') {
|
|
143
|
+
// HTTP 4xx/5xx — the URL was real-but-wrong or the upstream had issues.
|
|
144
|
+
// Either way, the tool worked; the agent should pick a different URL.
|
|
145
|
+
if (/^HTTP \d{3}\b/.test(out))
|
|
146
|
+
return false;
|
|
147
|
+
// Bad URL syntax / unsupported protocol / missing arg — agent input error.
|
|
148
|
+
if (out.startsWith('Error: invalid URL'))
|
|
149
|
+
return false;
|
|
150
|
+
if (out.startsWith('Error: only http'))
|
|
151
|
+
return false;
|
|
152
|
+
if (out.startsWith('Error: url is required'))
|
|
153
|
+
return false;
|
|
154
|
+
// User interrupt — not a tool failure.
|
|
155
|
+
if (out.startsWith('Error: request aborted'))
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
131
160
|
export class SessionToolGuard {
|
|
132
161
|
turn = 0;
|
|
133
162
|
webSearchesThisTurn = 0;
|
|
@@ -227,10 +256,15 @@ export class SessionToolGuard {
|
|
|
227
256
|
return null;
|
|
228
257
|
}
|
|
229
258
|
afterExecute(invocation, result) {
|
|
230
|
-
//
|
|
231
|
-
|
|
259
|
+
// Per-tool circuit breaker: count consecutive tool-class failures, reset on
|
|
260
|
+
// any success. Agent-input errors (e.g. WebFetch 404 on a guessed URL) are
|
|
261
|
+
// not tool failures and must not trip the breaker.
|
|
262
|
+
if (isToolClassFailure(invocation.name, result)) {
|
|
232
263
|
this.toolErrorCounts.set(invocation.name, (this.toolErrorCounts.get(invocation.name) ?? 0) + 1);
|
|
233
264
|
}
|
|
265
|
+
else if (!result.isError) {
|
|
266
|
+
this.toolErrorCounts.delete(invocation.name);
|
|
267
|
+
}
|
|
234
268
|
switch (invocation.name) {
|
|
235
269
|
case 'WebSearch':
|
|
236
270
|
case 'SearchX':
|
package/package.json
CHANGED