@theokit/sdk 2.13.1 → 2.15.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/CHANGELOG.md +12 -0
- package/dist/a2a/index.cjs +242 -3
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +242 -3
- package/dist/a2a/index.js.map +1 -1
- package/dist/{cron-CpxLdAXc.d.cts → cron-BxLSz1UH.d.cts} +1 -1
- package/dist/{cron-CL_9nfhQ.d.ts → cron-DcaoP7aW.d.ts} +1 -1
- package/dist/cron.cjs +225 -3
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +225 -3
- package/dist/cron.js.map +1 -1
- package/dist/define-tool.d.ts +8 -0
- package/dist/{errors-9yw4UQwX.d.cts → errors-Bart0ptP.d.cts} +1 -1
- package/dist/{errors-DFiY-NHK.d.ts → errors-DJuuubJK.d.ts} +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/eval.cjs +228 -6
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +228 -6
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +230 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -6
- package/dist/index.d.ts +41 -6
- package/dist/index.js +230 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/agent-loop/doom-loop-tracker.d.ts +22 -0
- package/dist/internal/agent-loop/loop-types.d.ts +6 -0
- package/dist/internal/llm/hermes-tool-extract.d.ts +1 -0
- package/dist/{run-TMdc7gmo.d.cts → run-DXy_MVwz.d.cts} +29 -1
- package/dist/{run-TMdc7gmo.d.ts → run-DXy_MVwz.d.ts} +29 -1
- package/dist/sanitize/coerce.d.cts +1 -0
- package/dist/sanitize/coerce.d.ts +1 -0
- package/dist/sanitize/index.cjs +119 -0
- package/dist/sanitize/index.cjs.map +1 -0
- package/dist/sanitize/index.d.cts +9 -0
- package/dist/sanitize/index.d.ts +9 -0
- package/dist/sanitize/index.js +116 -0
- package/dist/sanitize/index.js.map +1 -0
- package/dist/sanitize/sanitize-tool-input.d.cts +11 -0
- package/dist/sanitize/sanitize-tool-input.d.ts +11 -0
- package/dist/sanitize/types.d.cts +39 -0
- package/dist/sanitize/types.d.ts +39 -0
- package/dist/types/run.d.ts +28 -0
- package/package.json +13 -2
package/dist/define-tool.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { z as ZodNamespace, ZodType } from "zod";
|
|
2
|
+
import type { SanitizeOptions } from "./sanitize/types.js";
|
|
2
3
|
import type { CustomTool } from "./types/agent.js";
|
|
3
4
|
/**
|
|
4
5
|
* Spec accepted by {@link defineTool}. `inputSchema` is a Zod schema; the
|
|
@@ -15,6 +16,13 @@ export interface DefineToolSpec<T extends ZodType> {
|
|
|
15
16
|
inputSchema: T;
|
|
16
17
|
/** Handler invoked with the parsed input. Type is inferred via `z.infer<T>`. */
|
|
17
18
|
handler: (input: ZodNamespace.infer<T>) => string | Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Sanitize the raw model-emitted args BEFORE schema validation (`@theokit/sdk/sanitize`).
|
|
21
|
+
* `true` trims whitespace; an object opts into coercion / JSON-repair. Coercion is schema-aware
|
|
22
|
+
* against this tool's `inputSchema`. Absent ⇒ args reach validation untouched. Sanitize is
|
|
23
|
+
* hygiene, not a validity bypass — a genuinely invalid arg still raises `ZodError`.
|
|
24
|
+
*/
|
|
25
|
+
sanitize?: boolean | SanitizeOptions;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
20
28
|
* Type-safe builder for {@link CustomTool}. Converts a Zod schema to JSON
|
package/dist/errors.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { A as AgentDisposedError, c as AgentRunError, d as AgentRunErrorCode, e as AuthenticationError, g as BudgetExceededError, C as ConfigurationError, u as CredentialPoolExhaustedError, E as ErrorCode, m as ErrorMetadata, I as IntegrationNotConnectedError, n as InvalidTaskIdError, K as KnownAgentRunErrorCode, M as MemoryAdapterError, o as MemoryAdapterErrorCode, N as NetworkError, R as RateLimitError, p as TaskNotFoundError, T as TheokitAgentError, U as UnknownAgentError, q as UnsupportedBudgetOperationError, r as UnsupportedRunOperationError, s as UnsupportedTaskOperationError, t as isTransientError } from './errors-
|
|
2
|
-
import './run-
|
|
1
|
+
export { A as AgentDisposedError, c as AgentRunError, d as AgentRunErrorCode, e as AuthenticationError, g as BudgetExceededError, C as ConfigurationError, u as CredentialPoolExhaustedError, E as ErrorCode, m as ErrorMetadata, I as IntegrationNotConnectedError, n as InvalidTaskIdError, K as KnownAgentRunErrorCode, M as MemoryAdapterError, o as MemoryAdapterErrorCode, N as NetworkError, R as RateLimitError, p as TaskNotFoundError, T as TheokitAgentError, U as UnknownAgentError, q as UnsupportedBudgetOperationError, r as UnsupportedRunOperationError, s as UnsupportedTaskOperationError, t as isTransientError } from './errors-Bart0ptP.cjs';
|
|
2
|
+
import './run-DXy_MVwz.cjs';
|
package/dist/eval.cjs
CHANGED
|
@@ -1457,6 +1457,7 @@ function isEmptyRound(result) {
|
|
|
1457
1457
|
return (result.result ?? "").trim() === "";
|
|
1458
1458
|
}
|
|
1459
1459
|
function classifyRound(result, round, maxRounds, emptyStreak) {
|
|
1460
|
+
if (result.stoppedByDoomLoop === true) return "no_progress";
|
|
1460
1461
|
if (result.stoppedAtIterationLimit !== true) return "done";
|
|
1461
1462
|
if (isEmptyRound(result) && emptyStreak >= 1) return "no_progress";
|
|
1462
1463
|
if (round >= maxRounds) return "step_limit";
|
|
@@ -4490,6 +4491,7 @@ function applyScriptMetrics(base, script) {
|
|
|
4490
4491
|
if (script.usage !== void 0) base.usage = script.usage;
|
|
4491
4492
|
if (script.cost !== void 0) base.cost = script.cost;
|
|
4492
4493
|
if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
|
|
4494
|
+
if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
|
|
4493
4495
|
}
|
|
4494
4496
|
|
|
4495
4497
|
// src/internal/runtime/cloud/cloud-run.ts
|
|
@@ -8271,6 +8273,93 @@ function evaluateBudgetGate(tracker) {
|
|
|
8271
8273
|
}
|
|
8272
8274
|
}
|
|
8273
8275
|
|
|
8276
|
+
// src/internal/agent-loop/doom-loop-tracker.ts
|
|
8277
|
+
init_errors();
|
|
8278
|
+
function createDoomLoopTracker(option) {
|
|
8279
|
+
if (option === false) return void 0;
|
|
8280
|
+
return new DoomLoopTracker(option);
|
|
8281
|
+
}
|
|
8282
|
+
var DEFAULT_CONFIG = { softThreshold: 3, hardThreshold: 5 };
|
|
8283
|
+
function assertValidThresholds(soft, hard) {
|
|
8284
|
+
for (const [label, value] of [
|
|
8285
|
+
["softThreshold", soft],
|
|
8286
|
+
["hardThreshold", hard]
|
|
8287
|
+
]) {
|
|
8288
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
8289
|
+
throw new ConfigurationError(
|
|
8290
|
+
`doomLoop.${label} must be a positive integer (received ${value}).`,
|
|
8291
|
+
{ code: "invalid_doom_loop_threshold" }
|
|
8292
|
+
);
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
8295
|
+
}
|
|
8296
|
+
function sortKeys(value) {
|
|
8297
|
+
if (value === null || typeof value !== "object") return value;
|
|
8298
|
+
if (Array.isArray(value)) return value.map(sortKeys);
|
|
8299
|
+
const out = {};
|
|
8300
|
+
for (const key of Object.keys(value).sort()) {
|
|
8301
|
+
out[key] = sortKeys(value[key]);
|
|
8302
|
+
}
|
|
8303
|
+
return out;
|
|
8304
|
+
}
|
|
8305
|
+
function signatureOf(call) {
|
|
8306
|
+
const { input } = call;
|
|
8307
|
+
let inputSig;
|
|
8308
|
+
if (input === null || input === void 0) inputSig = "null";
|
|
8309
|
+
else if (typeof input !== "object") inputSig = String(input);
|
|
8310
|
+
else {
|
|
8311
|
+
try {
|
|
8312
|
+
inputSig = JSON.stringify(sortKeys(input)) ?? "null";
|
|
8313
|
+
} catch {
|
|
8314
|
+
inputSig = String(input);
|
|
8315
|
+
}
|
|
8316
|
+
}
|
|
8317
|
+
return `${call.name}\0${inputSig}`;
|
|
8318
|
+
}
|
|
8319
|
+
var DoomLoopTracker = class {
|
|
8320
|
+
#config;
|
|
8321
|
+
#lastSignature = "";
|
|
8322
|
+
#count = 0;
|
|
8323
|
+
constructor(config) {
|
|
8324
|
+
const softThreshold = config?.softThreshold ?? DEFAULT_CONFIG.softThreshold;
|
|
8325
|
+
const hardThreshold = config?.hardThreshold ?? DEFAULT_CONFIG.hardThreshold;
|
|
8326
|
+
assertValidThresholds(softThreshold, hardThreshold);
|
|
8327
|
+
this.#config = { softThreshold, hardThreshold };
|
|
8328
|
+
}
|
|
8329
|
+
inspect(call) {
|
|
8330
|
+
const signature = signatureOf(call);
|
|
8331
|
+
this.#count = signature === this.#lastSignature ? this.#count + 1 : 1;
|
|
8332
|
+
this.#lastSignature = signature;
|
|
8333
|
+
const count = this.#count;
|
|
8334
|
+
if (count >= this.#config.hardThreshold) {
|
|
8335
|
+
return {
|
|
8336
|
+
kind: "hard",
|
|
8337
|
+
message: `Detected ${count} consecutive identical calls to \`${call.name}\`; stopping to avoid a loop.`
|
|
8338
|
+
};
|
|
8339
|
+
}
|
|
8340
|
+
if (count === this.#config.softThreshold) {
|
|
8341
|
+
return {
|
|
8342
|
+
kind: "soft",
|
|
8343
|
+
message: `Detected ${count} consecutive identical calls to \`${call.name}\`; try a different approach.`
|
|
8344
|
+
};
|
|
8345
|
+
}
|
|
8346
|
+
return { kind: "ok" };
|
|
8347
|
+
}
|
|
8348
|
+
reset() {
|
|
8349
|
+
this.#lastSignature = "";
|
|
8350
|
+
this.#count = 0;
|
|
8351
|
+
}
|
|
8352
|
+
};
|
|
8353
|
+
function firstDoomLoopVerdict(tracker, calls) {
|
|
8354
|
+
let escalation = { kind: "ok" };
|
|
8355
|
+
for (const call of calls) {
|
|
8356
|
+
const v = tracker.inspect(call);
|
|
8357
|
+
if (v.kind === "hard") return v;
|
|
8358
|
+
if (v.kind === "soft" && escalation.kind === "ok") escalation = v;
|
|
8359
|
+
}
|
|
8360
|
+
return escalation;
|
|
8361
|
+
}
|
|
8362
|
+
|
|
8274
8363
|
// src/internal/budget/usage-accumulator.ts
|
|
8275
8364
|
var UsageAccumulator = class {
|
|
8276
8365
|
input = 0;
|
|
@@ -8451,6 +8540,7 @@ async function initLoopContext(inputs) {
|
|
|
8451
8540
|
tools,
|
|
8452
8541
|
finalText: "",
|
|
8453
8542
|
finalStatus: "finished",
|
|
8543
|
+
doomLoop: createDoomLoopTracker(inputs.doomLoop),
|
|
8454
8544
|
usage: new UsageAccumulator(),
|
|
8455
8545
|
nudgeAttempts: 0,
|
|
8456
8546
|
stopFeedbackAttempts: 0,
|
|
@@ -9475,6 +9565,7 @@ async function runAgentLoop(inputs) {
|
|
|
9475
9565
|
ctx.finalStatus = "error";
|
|
9476
9566
|
}
|
|
9477
9567
|
sendSpan?.setAttribute("status", ctx.finalStatus);
|
|
9568
|
+
if (ctx.stoppedByDoomLoop === true) sendSpan?.setAttribute("stoppedByDoomLoop", true);
|
|
9478
9569
|
if (inputs.telemetry?.includeContent === true && ctx.finalText.length > 0) {
|
|
9479
9570
|
sendSpan?.addEvent("response", { content: ctx.finalText });
|
|
9480
9571
|
}
|
|
@@ -9501,7 +9592,8 @@ async function runAgentLoop(inputs) {
|
|
|
9501
9592
|
...usage !== void 0 ? { usage } : {},
|
|
9502
9593
|
...cost !== void 0 ? { cost } : {},
|
|
9503
9594
|
...ctx.error !== void 0 ? { error: ctx.error } : {},
|
|
9504
|
-
...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {}
|
|
9595
|
+
...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {},
|
|
9596
|
+
...ctx.stoppedByDoomLoop === true ? { stoppedByDoomLoop: true } : {}
|
|
9505
9597
|
};
|
|
9506
9598
|
} finally {
|
|
9507
9599
|
if (ctxRef !== void 0 && ctxRef.memoryProviderHandle !== void 0 && inputs.memoryProvider !== void 0) {
|
|
@@ -9660,8 +9752,26 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
|
|
|
9660
9752
|
}
|
|
9661
9753
|
}
|
|
9662
9754
|
pushToolConversationSteps(ctx, llmOutput.toolCalls, toolResults);
|
|
9755
|
+
if (await inspectDoomLoop(inputs, ctx, llmOutput.toolCalls) === "stop") return "done";
|
|
9663
9756
|
return handleToolErrorContinuation(inputs, ctx, toolResults);
|
|
9664
9757
|
}
|
|
9758
|
+
async function inspectDoomLoop(inputs, ctx, toolCalls) {
|
|
9759
|
+
if (ctx.doomLoop === void 0) return "continue";
|
|
9760
|
+
const verdict = firstDoomLoopVerdict(ctx.doomLoop, toolCalls);
|
|
9761
|
+
if (verdict.kind === "hard") {
|
|
9762
|
+
ctx.stoppedByDoomLoop = true;
|
|
9763
|
+
await emitAssistantTextStep(
|
|
9764
|
+
inputs,
|
|
9765
|
+
ctx,
|
|
9766
|
+
verdict.message ?? "Stopped: repeated identical tool calls made no progress."
|
|
9767
|
+
);
|
|
9768
|
+
return "stop";
|
|
9769
|
+
}
|
|
9770
|
+
if (verdict.kind === "soft") {
|
|
9771
|
+
ctx.messages.push({ role: "user", content: [{ type: "text", text: verdict.message ?? "" }] });
|
|
9772
|
+
}
|
|
9773
|
+
return "continue";
|
|
9774
|
+
}
|
|
9665
9775
|
|
|
9666
9776
|
// src/internal/llm/fallback-client.ts
|
|
9667
9777
|
init_errors();
|
|
@@ -10950,6 +11060,115 @@ function toOllamaTools(tools) {
|
|
|
10950
11060
|
}
|
|
10951
11061
|
}));
|
|
10952
11062
|
}
|
|
11063
|
+
var cachedJsonrepair;
|
|
11064
|
+
function loadJsonrepair() {
|
|
11065
|
+
if (cachedJsonrepair === void 0) {
|
|
11066
|
+
const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('eval.cjs', document.baseURI).href)));
|
|
11067
|
+
cachedJsonrepair = req("jsonrepair").jsonrepair;
|
|
11068
|
+
}
|
|
11069
|
+
return cachedJsonrepair;
|
|
11070
|
+
}
|
|
11071
|
+
function isPlainObject(v) {
|
|
11072
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
11073
|
+
}
|
|
11074
|
+
function toFiniteNumber(raw) {
|
|
11075
|
+
if (raw === "") return void 0;
|
|
11076
|
+
const n = Number(raw);
|
|
11077
|
+
return Number.isFinite(n) && String(n) === raw ? n : void 0;
|
|
11078
|
+
}
|
|
11079
|
+
function tryJson(raw, repair) {
|
|
11080
|
+
const t = raw.trimStart();
|
|
11081
|
+
if (!(t.startsWith("{") || t.startsWith("["))) return void 0;
|
|
11082
|
+
try {
|
|
11083
|
+
return JSON.parse(repair ? loadJsonrepair()(t) : t);
|
|
11084
|
+
} catch {
|
|
11085
|
+
return void 0;
|
|
11086
|
+
}
|
|
11087
|
+
}
|
|
11088
|
+
function heuristicCoerce(raw, repairJson) {
|
|
11089
|
+
if (raw === "true") return true;
|
|
11090
|
+
if (raw === "false") return false;
|
|
11091
|
+
if (raw === "null") return null;
|
|
11092
|
+
const n = toFiniteNumber(raw);
|
|
11093
|
+
if (n !== void 0) return n;
|
|
11094
|
+
const json = tryJson(raw, false) ?? (repairJson ? tryJson(raw, true) : void 0);
|
|
11095
|
+
return json === void 0 ? raw : json;
|
|
11096
|
+
}
|
|
11097
|
+
function coerceCandidates(raw, repairJson) {
|
|
11098
|
+
const out = [];
|
|
11099
|
+
if (raw === "true") out.push(true);
|
|
11100
|
+
else if (raw === "false") out.push(false);
|
|
11101
|
+
else if (raw === "null") out.push(null);
|
|
11102
|
+
const n = toFiniteNumber(raw);
|
|
11103
|
+
if (n !== void 0) out.push(n);
|
|
11104
|
+
const json = tryJson(raw, false) ?? (repairJson ? tryJson(raw, true) : void 0);
|
|
11105
|
+
if (json !== void 0) out.push(json);
|
|
11106
|
+
out.push(raw);
|
|
11107
|
+
return out;
|
|
11108
|
+
}
|
|
11109
|
+
function objectShape(schema) {
|
|
11110
|
+
const shape = schema?.shape;
|
|
11111
|
+
return shape !== null && typeof shape === "object" ? shape : void 0;
|
|
11112
|
+
}
|
|
11113
|
+
|
|
11114
|
+
// src/sanitize/sanitize-tool-input.ts
|
|
11115
|
+
function applyTrim(key, value, ctx) {
|
|
11116
|
+
const trimmed = value.trim();
|
|
11117
|
+
if (trimmed !== value) ctx.notes.push(`trimmed "${key}"`);
|
|
11118
|
+
return trimmed;
|
|
11119
|
+
}
|
|
11120
|
+
function applyCoerce(key, raw, ctx) {
|
|
11121
|
+
const field = ctx.shape?.[key];
|
|
11122
|
+
let coerced = raw;
|
|
11123
|
+
if (field) {
|
|
11124
|
+
for (const candidate of coerceCandidates(raw, ctx.repairJson)) {
|
|
11125
|
+
if (field.safeParse(candidate).success) {
|
|
11126
|
+
coerced = candidate;
|
|
11127
|
+
break;
|
|
11128
|
+
}
|
|
11129
|
+
}
|
|
11130
|
+
} else {
|
|
11131
|
+
coerced = heuristicCoerce(raw, ctx.repairJson);
|
|
11132
|
+
}
|
|
11133
|
+
if (coerced !== raw) ctx.notes.push(`coerced "${key}"`);
|
|
11134
|
+
return coerced;
|
|
11135
|
+
}
|
|
11136
|
+
function applyRepair(key, value, ctx) {
|
|
11137
|
+
const repaired = tryJson(value, true);
|
|
11138
|
+
if (repaired === void 0) return value;
|
|
11139
|
+
ctx.notes.push(`repaired json "${key}"`);
|
|
11140
|
+
return repaired;
|
|
11141
|
+
}
|
|
11142
|
+
function sanitizeString(key, value, ctx) {
|
|
11143
|
+
let out = ctx.trim ? applyTrim(key, value, ctx) : value;
|
|
11144
|
+
if (ctx.coerce && typeof out === "string") out = applyCoerce(key, out, ctx);
|
|
11145
|
+
if (ctx.repairJson && !ctx.coerce && typeof out === "string") out = applyRepair(key, out, ctx);
|
|
11146
|
+
return out;
|
|
11147
|
+
}
|
|
11148
|
+
function walk(input, ctx, depth) {
|
|
11149
|
+
const out = {};
|
|
11150
|
+
for (const [key, value] of Object.entries(input)) {
|
|
11151
|
+
if (typeof value === "string") out[key] = sanitizeString(key, value, ctx);
|
|
11152
|
+
else if (ctx.deep && depth < ctx.maxDepth && isPlainObject(value))
|
|
11153
|
+
out[key] = walk(value, ctx, depth + 1);
|
|
11154
|
+
else out[key] = value;
|
|
11155
|
+
}
|
|
11156
|
+
return out;
|
|
11157
|
+
}
|
|
11158
|
+
function sanitizeToolInput(input, options) {
|
|
11159
|
+
if (!isPlainObject(input)) return { value: input, changed: false, notes: [] };
|
|
11160
|
+
const ctx = {
|
|
11161
|
+
trim: options?.trim,
|
|
11162
|
+
coerce: options?.coerce ?? false,
|
|
11163
|
+
repairJson: options?.repairJson ?? false,
|
|
11164
|
+
deep: options?.deep ?? false,
|
|
11165
|
+
maxDepth: options?.maxDepth ?? 8,
|
|
11166
|
+
shape: objectShape(options?.schema),
|
|
11167
|
+
notes: []
|
|
11168
|
+
};
|
|
11169
|
+
const value = walk(input, ctx, 0);
|
|
11170
|
+
return { value, changed: ctx.notes.length > 0, notes: ctx.notes };
|
|
11171
|
+
}
|
|
10953
11172
|
|
|
10954
11173
|
// src/internal/llm/hermes-tool-extract.ts
|
|
10955
11174
|
var HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
|
|
@@ -10975,9 +11194,9 @@ function parseHermesParams(inner) {
|
|
|
10975
11194
|
const key = param[1];
|
|
10976
11195
|
const value = param[2];
|
|
10977
11196
|
if (key === void 0 || value === void 0) continue;
|
|
10978
|
-
input[key.trim()] = value
|
|
11197
|
+
input[key.trim()] = value;
|
|
10979
11198
|
}
|
|
10980
|
-
return input;
|
|
11199
|
+
return sanitizeToolInput(input, { trim: true }).value;
|
|
10981
11200
|
}
|
|
10982
11201
|
|
|
10983
11202
|
// src/internal/llm/openai.ts
|
|
@@ -12097,6 +12316,8 @@ function buildLoopInputs(options, runId, userText) {
|
|
|
12097
12316
|
// M1-2: per-send iteration ceiling (validated above). The loop reads
|
|
12098
12317
|
// inputs.maxIterations (default 8 when unset).
|
|
12099
12318
|
...maxIterations !== void 0 ? { maxIterations } : {},
|
|
12319
|
+
// Doom-loop guard config (default on; `false` disables, object tunes thresholds).
|
|
12320
|
+
...options.sendOptions.doomLoop !== void 0 ? { doomLoop: options.sendOptions.doomLoop } : {},
|
|
12100
12321
|
// D315-D317 — tool lifecycle hooks (cost tracking + audit + retry/alert)
|
|
12101
12322
|
...options.agentOptions.onToolStart !== void 0 ? { onToolStart: options.agentOptions.onToolStart } : {},
|
|
12102
12323
|
...options.agentOptions.onToolEnd !== void 0 ? { onToolEnd: options.agentOptions.onToolEnd } : {},
|
|
@@ -12229,6 +12450,7 @@ var RealLocalRun = class extends FixtureRunBase {
|
|
|
12229
12450
|
if (output.usage !== void 0) this.script.usage = output.usage;
|
|
12230
12451
|
if (output.cost !== void 0) this.script.cost = output.cost;
|
|
12231
12452
|
if (output.stoppedAtIterationLimit === true) this.script.stoppedAtIterationLimit = true;
|
|
12453
|
+
if (output.stoppedByDoomLoop === true) this.script.stoppedByDoomLoop = true;
|
|
12232
12454
|
if (output.error !== void 0 && this.script.errorDetail === void 0) {
|
|
12233
12455
|
this.script.errorDetail = {
|
|
12234
12456
|
message: output.error.message,
|
|
@@ -15787,7 +16009,7 @@ var JsonlParseError = class extends Error {
|
|
|
15787
16009
|
}
|
|
15788
16010
|
line;
|
|
15789
16011
|
};
|
|
15790
|
-
function
|
|
16012
|
+
function isPlainObject2(value) {
|
|
15791
16013
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15792
16014
|
}
|
|
15793
16015
|
function tryParseObjectLine(line) {
|
|
@@ -15798,7 +16020,7 @@ function tryParseObjectLine(line) {
|
|
|
15798
16020
|
} catch {
|
|
15799
16021
|
return void 0;
|
|
15800
16022
|
}
|
|
15801
|
-
return
|
|
16023
|
+
return isPlainObject2(parsed) ? parsed : void 0;
|
|
15802
16024
|
}
|
|
15803
16025
|
function loadJsonl(path, opts = {}) {
|
|
15804
16026
|
const text = fs.readFileSync(path, "utf8");
|
|
@@ -15814,7 +16036,7 @@ function loadJsonl(path, opts = {}) {
|
|
|
15814
16036
|
} catch {
|
|
15815
16037
|
throw new JsonlParseError(`line ${lineNumber}: invalid JSON`, lineNumber);
|
|
15816
16038
|
}
|
|
15817
|
-
if (!
|
|
16039
|
+
if (!isPlainObject2(parsed)) {
|
|
15818
16040
|
throw new JsonlParseError(`line ${lineNumber}: not a JSON object`, lineNumber);
|
|
15819
16041
|
}
|
|
15820
16042
|
out.push(opts.map ? opts.map(parsed, lineNumber) : parsed);
|