@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/cron.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import './run-
|
|
2
|
-
export { K as Cron } from './cron-
|
|
1
|
+
import './run-DXy_MVwz.cjs';
|
|
2
|
+
export { K as Cron } from './cron-BxLSz1UH.cjs';
|
package/dist/cron.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import './run-
|
|
2
|
-
export { K as Cron } from './cron-
|
|
1
|
+
import './run-DXy_MVwz.js';
|
|
2
|
+
export { K as Cron } from './cron-DcaoP7aW.js';
|
package/dist/cron.js
CHANGED
|
@@ -1455,6 +1455,7 @@ function isEmptyRound(result) {
|
|
|
1455
1455
|
return (result.result ?? "").trim() === "";
|
|
1456
1456
|
}
|
|
1457
1457
|
function classifyRound(result, round, maxRounds, emptyStreak) {
|
|
1458
|
+
if (result.stoppedByDoomLoop === true) return "no_progress";
|
|
1458
1459
|
if (result.stoppedAtIterationLimit !== true) return "done";
|
|
1459
1460
|
if (isEmptyRound(result) && emptyStreak >= 1) return "no_progress";
|
|
1460
1461
|
if (round >= maxRounds) return "step_limit";
|
|
@@ -4492,6 +4493,7 @@ function applyScriptMetrics(base, script) {
|
|
|
4492
4493
|
if (script.usage !== void 0) base.usage = script.usage;
|
|
4493
4494
|
if (script.cost !== void 0) base.cost = script.cost;
|
|
4494
4495
|
if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
|
|
4496
|
+
if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
|
|
4495
4497
|
}
|
|
4496
4498
|
|
|
4497
4499
|
// src/internal/runtime/cloud/cloud-run.ts
|
|
@@ -8273,6 +8275,93 @@ function evaluateBudgetGate(tracker) {
|
|
|
8273
8275
|
}
|
|
8274
8276
|
}
|
|
8275
8277
|
|
|
8278
|
+
// src/internal/agent-loop/doom-loop-tracker.ts
|
|
8279
|
+
init_errors();
|
|
8280
|
+
function createDoomLoopTracker(option) {
|
|
8281
|
+
if (option === false) return void 0;
|
|
8282
|
+
return new DoomLoopTracker(option);
|
|
8283
|
+
}
|
|
8284
|
+
var DEFAULT_CONFIG = { softThreshold: 3, hardThreshold: 5 };
|
|
8285
|
+
function assertValidThresholds(soft, hard) {
|
|
8286
|
+
for (const [label, value] of [
|
|
8287
|
+
["softThreshold", soft],
|
|
8288
|
+
["hardThreshold", hard]
|
|
8289
|
+
]) {
|
|
8290
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
8291
|
+
throw new ConfigurationError(
|
|
8292
|
+
`doomLoop.${label} must be a positive integer (received ${value}).`,
|
|
8293
|
+
{ code: "invalid_doom_loop_threshold" }
|
|
8294
|
+
);
|
|
8295
|
+
}
|
|
8296
|
+
}
|
|
8297
|
+
}
|
|
8298
|
+
function sortKeys(value) {
|
|
8299
|
+
if (value === null || typeof value !== "object") return value;
|
|
8300
|
+
if (Array.isArray(value)) return value.map(sortKeys);
|
|
8301
|
+
const out = {};
|
|
8302
|
+
for (const key of Object.keys(value).sort()) {
|
|
8303
|
+
out[key] = sortKeys(value[key]);
|
|
8304
|
+
}
|
|
8305
|
+
return out;
|
|
8306
|
+
}
|
|
8307
|
+
function signatureOf(call) {
|
|
8308
|
+
const { input } = call;
|
|
8309
|
+
let inputSig;
|
|
8310
|
+
if (input === null || input === void 0) inputSig = "null";
|
|
8311
|
+
else if (typeof input !== "object") inputSig = String(input);
|
|
8312
|
+
else {
|
|
8313
|
+
try {
|
|
8314
|
+
inputSig = JSON.stringify(sortKeys(input)) ?? "null";
|
|
8315
|
+
} catch {
|
|
8316
|
+
inputSig = String(input);
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
return `${call.name}\0${inputSig}`;
|
|
8320
|
+
}
|
|
8321
|
+
var DoomLoopTracker = class {
|
|
8322
|
+
#config;
|
|
8323
|
+
#lastSignature = "";
|
|
8324
|
+
#count = 0;
|
|
8325
|
+
constructor(config) {
|
|
8326
|
+
const softThreshold = config?.softThreshold ?? DEFAULT_CONFIG.softThreshold;
|
|
8327
|
+
const hardThreshold = config?.hardThreshold ?? DEFAULT_CONFIG.hardThreshold;
|
|
8328
|
+
assertValidThresholds(softThreshold, hardThreshold);
|
|
8329
|
+
this.#config = { softThreshold, hardThreshold };
|
|
8330
|
+
}
|
|
8331
|
+
inspect(call) {
|
|
8332
|
+
const signature = signatureOf(call);
|
|
8333
|
+
this.#count = signature === this.#lastSignature ? this.#count + 1 : 1;
|
|
8334
|
+
this.#lastSignature = signature;
|
|
8335
|
+
const count = this.#count;
|
|
8336
|
+
if (count >= this.#config.hardThreshold) {
|
|
8337
|
+
return {
|
|
8338
|
+
kind: "hard",
|
|
8339
|
+
message: `Detected ${count} consecutive identical calls to \`${call.name}\`; stopping to avoid a loop.`
|
|
8340
|
+
};
|
|
8341
|
+
}
|
|
8342
|
+
if (count === this.#config.softThreshold) {
|
|
8343
|
+
return {
|
|
8344
|
+
kind: "soft",
|
|
8345
|
+
message: `Detected ${count} consecutive identical calls to \`${call.name}\`; try a different approach.`
|
|
8346
|
+
};
|
|
8347
|
+
}
|
|
8348
|
+
return { kind: "ok" };
|
|
8349
|
+
}
|
|
8350
|
+
reset() {
|
|
8351
|
+
this.#lastSignature = "";
|
|
8352
|
+
this.#count = 0;
|
|
8353
|
+
}
|
|
8354
|
+
};
|
|
8355
|
+
function firstDoomLoopVerdict(tracker, calls) {
|
|
8356
|
+
let escalation = { kind: "ok" };
|
|
8357
|
+
for (const call of calls) {
|
|
8358
|
+
const v = tracker.inspect(call);
|
|
8359
|
+
if (v.kind === "hard") return v;
|
|
8360
|
+
if (v.kind === "soft" && escalation.kind === "ok") escalation = v;
|
|
8361
|
+
}
|
|
8362
|
+
return escalation;
|
|
8363
|
+
}
|
|
8364
|
+
|
|
8276
8365
|
// src/internal/budget/usage-accumulator.ts
|
|
8277
8366
|
var UsageAccumulator = class {
|
|
8278
8367
|
input = 0;
|
|
@@ -8453,6 +8542,7 @@ async function initLoopContext(inputs) {
|
|
|
8453
8542
|
tools,
|
|
8454
8543
|
finalText: "",
|
|
8455
8544
|
finalStatus: "finished",
|
|
8545
|
+
doomLoop: createDoomLoopTracker(inputs.doomLoop),
|
|
8456
8546
|
usage: new UsageAccumulator(),
|
|
8457
8547
|
nudgeAttempts: 0,
|
|
8458
8548
|
stopFeedbackAttempts: 0,
|
|
@@ -9477,6 +9567,7 @@ async function runAgentLoop(inputs) {
|
|
|
9477
9567
|
ctx.finalStatus = "error";
|
|
9478
9568
|
}
|
|
9479
9569
|
sendSpan?.setAttribute("status", ctx.finalStatus);
|
|
9570
|
+
if (ctx.stoppedByDoomLoop === true) sendSpan?.setAttribute("stoppedByDoomLoop", true);
|
|
9480
9571
|
if (inputs.telemetry?.includeContent === true && ctx.finalText.length > 0) {
|
|
9481
9572
|
sendSpan?.addEvent("response", { content: ctx.finalText });
|
|
9482
9573
|
}
|
|
@@ -9503,7 +9594,8 @@ async function runAgentLoop(inputs) {
|
|
|
9503
9594
|
...usage !== void 0 ? { usage } : {},
|
|
9504
9595
|
...cost !== void 0 ? { cost } : {},
|
|
9505
9596
|
...ctx.error !== void 0 ? { error: ctx.error } : {},
|
|
9506
|
-
...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {}
|
|
9597
|
+
...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {},
|
|
9598
|
+
...ctx.stoppedByDoomLoop === true ? { stoppedByDoomLoop: true } : {}
|
|
9507
9599
|
};
|
|
9508
9600
|
} finally {
|
|
9509
9601
|
if (ctxRef !== void 0 && ctxRef.memoryProviderHandle !== void 0 && inputs.memoryProvider !== void 0) {
|
|
@@ -9662,8 +9754,26 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
|
|
|
9662
9754
|
}
|
|
9663
9755
|
}
|
|
9664
9756
|
pushToolConversationSteps(ctx, llmOutput.toolCalls, toolResults);
|
|
9757
|
+
if (await inspectDoomLoop(inputs, ctx, llmOutput.toolCalls) === "stop") return "done";
|
|
9665
9758
|
return handleToolErrorContinuation(inputs, ctx, toolResults);
|
|
9666
9759
|
}
|
|
9760
|
+
async function inspectDoomLoop(inputs, ctx, toolCalls) {
|
|
9761
|
+
if (ctx.doomLoop === void 0) return "continue";
|
|
9762
|
+
const verdict = firstDoomLoopVerdict(ctx.doomLoop, toolCalls);
|
|
9763
|
+
if (verdict.kind === "hard") {
|
|
9764
|
+
ctx.stoppedByDoomLoop = true;
|
|
9765
|
+
await emitAssistantTextStep(
|
|
9766
|
+
inputs,
|
|
9767
|
+
ctx,
|
|
9768
|
+
verdict.message ?? "Stopped: repeated identical tool calls made no progress."
|
|
9769
|
+
);
|
|
9770
|
+
return "stop";
|
|
9771
|
+
}
|
|
9772
|
+
if (verdict.kind === "soft") {
|
|
9773
|
+
ctx.messages.push({ role: "user", content: [{ type: "text", text: verdict.message ?? "" }] });
|
|
9774
|
+
}
|
|
9775
|
+
return "continue";
|
|
9776
|
+
}
|
|
9667
9777
|
|
|
9668
9778
|
// src/internal/llm/fallback-client.ts
|
|
9669
9779
|
init_errors();
|
|
@@ -10952,6 +11062,115 @@ function toOllamaTools(tools) {
|
|
|
10952
11062
|
}
|
|
10953
11063
|
}));
|
|
10954
11064
|
}
|
|
11065
|
+
var cachedJsonrepair;
|
|
11066
|
+
function loadJsonrepair() {
|
|
11067
|
+
if (cachedJsonrepair === void 0) {
|
|
11068
|
+
const req = createRequire(import.meta.url);
|
|
11069
|
+
cachedJsonrepair = req("jsonrepair").jsonrepair;
|
|
11070
|
+
}
|
|
11071
|
+
return cachedJsonrepair;
|
|
11072
|
+
}
|
|
11073
|
+
function isPlainObject(v) {
|
|
11074
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
11075
|
+
}
|
|
11076
|
+
function toFiniteNumber(raw) {
|
|
11077
|
+
if (raw === "") return void 0;
|
|
11078
|
+
const n = Number(raw);
|
|
11079
|
+
return Number.isFinite(n) && String(n) === raw ? n : void 0;
|
|
11080
|
+
}
|
|
11081
|
+
function tryJson(raw, repair) {
|
|
11082
|
+
const t = raw.trimStart();
|
|
11083
|
+
if (!(t.startsWith("{") || t.startsWith("["))) return void 0;
|
|
11084
|
+
try {
|
|
11085
|
+
return JSON.parse(repair ? loadJsonrepair()(t) : t);
|
|
11086
|
+
} catch {
|
|
11087
|
+
return void 0;
|
|
11088
|
+
}
|
|
11089
|
+
}
|
|
11090
|
+
function heuristicCoerce(raw, repairJson) {
|
|
11091
|
+
if (raw === "true") return true;
|
|
11092
|
+
if (raw === "false") return false;
|
|
11093
|
+
if (raw === "null") return null;
|
|
11094
|
+
const n = toFiniteNumber(raw);
|
|
11095
|
+
if (n !== void 0) return n;
|
|
11096
|
+
const json = tryJson(raw, false) ?? (repairJson ? tryJson(raw, true) : void 0);
|
|
11097
|
+
return json === void 0 ? raw : json;
|
|
11098
|
+
}
|
|
11099
|
+
function coerceCandidates(raw, repairJson) {
|
|
11100
|
+
const out = [];
|
|
11101
|
+
if (raw === "true") out.push(true);
|
|
11102
|
+
else if (raw === "false") out.push(false);
|
|
11103
|
+
else if (raw === "null") out.push(null);
|
|
11104
|
+
const n = toFiniteNumber(raw);
|
|
11105
|
+
if (n !== void 0) out.push(n);
|
|
11106
|
+
const json = tryJson(raw, false) ?? (repairJson ? tryJson(raw, true) : void 0);
|
|
11107
|
+
if (json !== void 0) out.push(json);
|
|
11108
|
+
out.push(raw);
|
|
11109
|
+
return out;
|
|
11110
|
+
}
|
|
11111
|
+
function objectShape(schema) {
|
|
11112
|
+
const shape = schema?.shape;
|
|
11113
|
+
return shape !== null && typeof shape === "object" ? shape : void 0;
|
|
11114
|
+
}
|
|
11115
|
+
|
|
11116
|
+
// src/sanitize/sanitize-tool-input.ts
|
|
11117
|
+
function applyTrim(key, value, ctx) {
|
|
11118
|
+
const trimmed = value.trim();
|
|
11119
|
+
if (trimmed !== value) ctx.notes.push(`trimmed "${key}"`);
|
|
11120
|
+
return trimmed;
|
|
11121
|
+
}
|
|
11122
|
+
function applyCoerce(key, raw, ctx) {
|
|
11123
|
+
const field = ctx.shape?.[key];
|
|
11124
|
+
let coerced = raw;
|
|
11125
|
+
if (field) {
|
|
11126
|
+
for (const candidate of coerceCandidates(raw, ctx.repairJson)) {
|
|
11127
|
+
if (field.safeParse(candidate).success) {
|
|
11128
|
+
coerced = candidate;
|
|
11129
|
+
break;
|
|
11130
|
+
}
|
|
11131
|
+
}
|
|
11132
|
+
} else {
|
|
11133
|
+
coerced = heuristicCoerce(raw, ctx.repairJson);
|
|
11134
|
+
}
|
|
11135
|
+
if (coerced !== raw) ctx.notes.push(`coerced "${key}"`);
|
|
11136
|
+
return coerced;
|
|
11137
|
+
}
|
|
11138
|
+
function applyRepair(key, value, ctx) {
|
|
11139
|
+
const repaired = tryJson(value, true);
|
|
11140
|
+
if (repaired === void 0) return value;
|
|
11141
|
+
ctx.notes.push(`repaired json "${key}"`);
|
|
11142
|
+
return repaired;
|
|
11143
|
+
}
|
|
11144
|
+
function sanitizeString(key, value, ctx) {
|
|
11145
|
+
let out = ctx.trim ? applyTrim(key, value, ctx) : value;
|
|
11146
|
+
if (ctx.coerce && typeof out === "string") out = applyCoerce(key, out, ctx);
|
|
11147
|
+
if (ctx.repairJson && !ctx.coerce && typeof out === "string") out = applyRepair(key, out, ctx);
|
|
11148
|
+
return out;
|
|
11149
|
+
}
|
|
11150
|
+
function walk(input, ctx, depth) {
|
|
11151
|
+
const out = {};
|
|
11152
|
+
for (const [key, value] of Object.entries(input)) {
|
|
11153
|
+
if (typeof value === "string") out[key] = sanitizeString(key, value, ctx);
|
|
11154
|
+
else if (ctx.deep && depth < ctx.maxDepth && isPlainObject(value))
|
|
11155
|
+
out[key] = walk(value, ctx, depth + 1);
|
|
11156
|
+
else out[key] = value;
|
|
11157
|
+
}
|
|
11158
|
+
return out;
|
|
11159
|
+
}
|
|
11160
|
+
function sanitizeToolInput(input, options) {
|
|
11161
|
+
if (!isPlainObject(input)) return { value: input, changed: false, notes: [] };
|
|
11162
|
+
const ctx = {
|
|
11163
|
+
trim: options?.trim,
|
|
11164
|
+
coerce: options?.coerce ?? false,
|
|
11165
|
+
repairJson: options?.repairJson ?? false,
|
|
11166
|
+
deep: options?.deep ?? false,
|
|
11167
|
+
maxDepth: options?.maxDepth ?? 8,
|
|
11168
|
+
shape: objectShape(options?.schema),
|
|
11169
|
+
notes: []
|
|
11170
|
+
};
|
|
11171
|
+
const value = walk(input, ctx, 0);
|
|
11172
|
+
return { value, changed: ctx.notes.length > 0, notes: ctx.notes };
|
|
11173
|
+
}
|
|
10955
11174
|
|
|
10956
11175
|
// src/internal/llm/hermes-tool-extract.ts
|
|
10957
11176
|
var HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
|
|
@@ -10977,9 +11196,9 @@ function parseHermesParams(inner) {
|
|
|
10977
11196
|
const key = param[1];
|
|
10978
11197
|
const value = param[2];
|
|
10979
11198
|
if (key === void 0 || value === void 0) continue;
|
|
10980
|
-
input[key.trim()] = value
|
|
11199
|
+
input[key.trim()] = value;
|
|
10981
11200
|
}
|
|
10982
|
-
return input;
|
|
11201
|
+
return sanitizeToolInput(input, { trim: true }).value;
|
|
10983
11202
|
}
|
|
10984
11203
|
|
|
10985
11204
|
// src/internal/llm/openai.ts
|
|
@@ -12099,6 +12318,8 @@ function buildLoopInputs(options, runId, userText) {
|
|
|
12099
12318
|
// M1-2: per-send iteration ceiling (validated above). The loop reads
|
|
12100
12319
|
// inputs.maxIterations (default 8 when unset).
|
|
12101
12320
|
...maxIterations !== void 0 ? { maxIterations } : {},
|
|
12321
|
+
// Doom-loop guard config (default on; `false` disables, object tunes thresholds).
|
|
12322
|
+
...options.sendOptions.doomLoop !== void 0 ? { doomLoop: options.sendOptions.doomLoop } : {},
|
|
12102
12323
|
// D315-D317 — tool lifecycle hooks (cost tracking + audit + retry/alert)
|
|
12103
12324
|
...options.agentOptions.onToolStart !== void 0 ? { onToolStart: options.agentOptions.onToolStart } : {},
|
|
12104
12325
|
...options.agentOptions.onToolEnd !== void 0 ? { onToolEnd: options.agentOptions.onToolEnd } : {},
|
|
@@ -12231,6 +12452,7 @@ var RealLocalRun = class extends FixtureRunBase {
|
|
|
12231
12452
|
if (output.usage !== void 0) this.script.usage = output.usage;
|
|
12232
12453
|
if (output.cost !== void 0) this.script.cost = output.cost;
|
|
12233
12454
|
if (output.stoppedAtIterationLimit === true) this.script.stoppedAtIterationLimit = true;
|
|
12455
|
+
if (output.stoppedByDoomLoop === true) this.script.stoppedByDoomLoop = true;
|
|
12234
12456
|
if (output.error !== void 0 && this.script.errorDetail === void 0) {
|
|
12235
12457
|
this.script.errorDetail = {
|
|
12236
12458
|
message: output.error.message,
|