@theokit/sdk 2.0.1 → 2.2.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 +28 -0
- package/dist/a2a/index.cjs +261 -174
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +261 -174
- package/dist/a2a/index.js.map +1 -1
- package/dist/concurrency.cjs +86 -0
- package/dist/concurrency.cjs.map +1 -0
- package/dist/concurrency.d.cts +13 -0
- package/dist/concurrency.d.ts +13 -0
- package/dist/concurrency.js +83 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/{cron-Bj8-Aq1O.d.ts → cron-Aksw2Hy4.d.ts} +10 -2
- package/dist/{cron-DFG9-W17.d.cts → cron-JSPSFczQ.d.cts} +10 -2
- package/dist/cron.cjs +244 -172
- 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 +244 -172
- package/dist/cron.js.map +1 -1
- package/dist/{errors-ChqOmFH1.d.cts → errors-Bcw_Pakm.d.ts} +24 -2
- package/dist/{errors-DV9e0rcp.d.ts → errors-Vhg6ZV4o.d.cts} +24 -2
- package/dist/errors.cjs +17 -11
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +17 -12
- package/dist/errors.js.map +1 -1
- package/dist/eval.cjs +244 -172
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +244 -172
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +262 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +163 -121
- package/dist/index.d.ts +163 -121
- package/dist/index.js +262 -176
- package/dist/index.js.map +1 -1
- package/dist/internal/agent-loop/loop-types.d.ts +6 -0
- package/dist/internal/default-retriable.d.ts +1 -0
- package/dist/internal/persistence/index.cjs +75 -0
- package/dist/internal/persistence/index.cjs.map +1 -1
- package/dist/internal/persistence/index.d.cts +2 -0
- package/dist/internal/persistence/index.d.ts +2 -0
- package/dist/internal/persistence/index.js +74 -1
- package/dist/internal/persistence/index.js.map +1 -1
- package/dist/internal/persistence/sqlite-open.d.cts +47 -0
- package/dist/internal/persistence/sqlite-open.d.ts +47 -0
- package/dist/internal/providers/register-plugin-providers.d.ts +22 -0
- package/dist/internal/runtime/budget/budget-tracker.d.ts +8 -0
- package/dist/internal/runtime/concurrency/map-with-concurrency.d.ts +28 -0
- package/dist/internal/runtime/retry/with-retry.d.ts +40 -0
- package/dist/internal/security/index.cjs +1 -0
- package/dist/internal/security/index.cjs.map +1 -1
- package/dist/internal/security/index.js +1 -0
- package/dist/internal/security/index.js.map +1 -1
- package/dist/path-safety.cjs +15 -0
- package/dist/path-safety.cjs.map +1 -1
- package/dist/path-safety.d.cts +1 -1
- package/dist/path-safety.d.ts +1 -1
- package/dist/path-safety.js +15 -1
- package/dist/path-safety.js.map +1 -1
- package/dist/retry.cjs +85 -0
- package/dist/retry.cjs.map +1 -0
- package/dist/retry.d.cts +9 -0
- package/dist/retry.d.ts +9 -0
- package/dist/retry.js +83 -0
- package/dist/retry.js.map +1 -0
- package/dist/{run-DrwUpFxZ.d.cts → run-ekGKZlmg.d.cts} +20 -0
- package/dist/{run-DrwUpFxZ.d.ts → run-ekGKZlmg.d.ts} +20 -0
- package/dist/server/errors-envelope.cjs +14 -12
- package/dist/server/errors-envelope.cjs.map +1 -1
- package/dist/server/errors-envelope.js +14 -12
- package/dist/server/errors-envelope.js.map +1 -1
- package/dist/subscription/index.cjs.map +1 -1
- package/dist/subscription/index.js.map +1 -1
- package/dist/task-store.cjs.map +1 -1
- package/dist/task-store.js.map +1 -1
- package/dist/types/run.d.ts +20 -0
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.js.map +1 -1
- package/package.json +21 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- efe183e: M1 Reliable harness — make the agent loop's iteration ceiling real (plan `m1-reliable-harness`).
|
|
8
|
+
|
|
9
|
+
- **M1-1:** the agent loop now calls `BudgetTracker.nextIteration?.()` once per completed turn, and `nextIteration?()` is an optional member of the `BudgetTracker` interface. `createCounterBudgetTracker({ maxIterations: N })` now actually halts the loop after N turns (it was dead — nothing called it). Additive and backward-compatible: trackers that only gate on tokens/USD omit the method.
|
|
10
|
+
- **M1-2 (knob):** `SendOptions.maxIterations` lets a builder raise/lower the loop's default 8-turn cap per `agent.send` call. Validated at the boundary (positive integer; invalid throws `ConfigurationError`). Default of 8 preserved when unset.
|
|
11
|
+
- **M1-2 (truncation signal):** `RunResult.stoppedAtIterationLimit` is `true` when the loop stopped at its iteration ceiling with tool work still pending (silent truncation) vs a clean `done` finish. Lets a caller/continuation driver detect and recover.
|
|
12
|
+
|
|
13
|
+
## 2.1.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 7d53632: Custom LLM providers via the public Plugin protocol (plan `dev-friendly-custom-provider`).
|
|
18
|
+
|
|
19
|
+
- **Added** `defineProvider(profile, opts?)` — canonical factory (mirrors `defineTool`/`definePlugin`, Inviolable Rule 9) that wraps a data-only `ProviderProfile` into a `kind: "model-provider"` `Plugin`. Register any OpenAI-/Anthropic-compatible endpoint (Groq, Together, Fireworks, DeepInfra, a private gateway) with `Agent.create({ model: { id: "myprov/model" }, plugins: [defineProvider(profile)] })`, routed via the `provider/model` id prefix. Exported from `@theokit/sdk`.
|
|
20
|
+
- **Fixed** half-wired `kind: "model-provider"` plugin path: `PluginManager` aggregated provider profiles but nothing registered them, so `getProviderProfile`/`resolveProviderChain` never saw a plugin-contributed provider — a programmatic `model-provider` plugin was silently dropped. The local-agent run now registers plugin-contributed profiles before provider-chain resolution, so custom providers actually route.
|
|
21
|
+
- **Docs** new "Custom providers (`defineProvider`)" section in `docs.md` (field reference + `apiMode` table) and a worked `examples/custom-provider/`.
|
|
22
|
+
|
|
23
|
+
- 872c89e: M0 Foundation — expose already-existing internal primitives as public surfaces (plan `m0-foundation-expose-primitives`), so agent/code-assistant builders reuse battle-tested plumbing instead of re-implementing it.
|
|
24
|
+
|
|
25
|
+
- `isTransientError(err)` — public retryability predicate delegating to `TheokitAgentError.isRetryable` (T1.1).
|
|
26
|
+
- `safeFilenameForId(id, { maxLen })` — total id→filename helper via `@theokit/sdk/path-safety` (passthrough when safe, deterministic sha256 token otherwise); `sanitizeRunId` migrated to it (T2.1).
|
|
27
|
+
- `@theokit/sdk/concurrency` — public `createSemaphore` + new ordered, fail-fast `mapWithConcurrency`; two internal pooling clones deduplicated onto it (T3.1).
|
|
28
|
+
- `@theokit/sdk/retry` — generic `withRetry(fn, options)` (exponential backoff + full jitter, injectable sleep/rng, default `isRetryable = isTransientError`) (T4.1).
|
|
29
|
+
- `openSqliteResilient` (`@theokit/sdk/internal/persistence`, semver-exempt) — shared driver-load + WAL + corruption-recovery; both memory `index-db` copies deduplicated onto it (T5.1).
|
|
30
|
+
|
|
3
31
|
## 2.0.1
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/a2a/index.cjs
CHANGED
|
@@ -132,6 +132,24 @@ var init_agent_builder = __esm({
|
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
+
// src/internal/default-retriable.ts
|
|
136
|
+
function defaultRetriableForCode(code) {
|
|
137
|
+
switch (code) {
|
|
138
|
+
case "rate_limit":
|
|
139
|
+
case "timeout":
|
|
140
|
+
case "server_error":
|
|
141
|
+
case "network":
|
|
142
|
+
case "provider_unreachable":
|
|
143
|
+
return true;
|
|
144
|
+
default:
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
var init_default_retriable = __esm({
|
|
149
|
+
"src/internal/default-retriable.ts"() {
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
135
153
|
// src/internal/security/redact.ts
|
|
136
154
|
function readEnvOnce() {
|
|
137
155
|
const raw = process.env.THEOKIT_REDACT_SECRETS;
|
|
@@ -282,7 +300,8 @@ __export(errors_exports, {
|
|
|
282
300
|
UnsupportedBudgetOperationError: () => UnsupportedBudgetOperationError,
|
|
283
301
|
UnsupportedRunOperationError: () => UnsupportedRunOperationError,
|
|
284
302
|
UnsupportedTaskOperationError: () => UnsupportedTaskOperationError,
|
|
285
|
-
coerceToKnownAgentRunErrorCode: () => coerceToKnownAgentRunErrorCode
|
|
303
|
+
coerceToKnownAgentRunErrorCode: () => coerceToKnownAgentRunErrorCode,
|
|
304
|
+
isTransientError: () => isTransientError
|
|
286
305
|
});
|
|
287
306
|
function coerceToKnownAgentRunErrorCode(code) {
|
|
288
307
|
if (code !== void 0 && KNOWN_AGENT_RUN_ERROR_CODES.has(code)) {
|
|
@@ -314,21 +333,13 @@ function safeStringify(value) {
|
|
|
314
333
|
return String(value);
|
|
315
334
|
}
|
|
316
335
|
}
|
|
317
|
-
function
|
|
318
|
-
|
|
319
|
-
case "rate_limit":
|
|
320
|
-
case "timeout":
|
|
321
|
-
case "server_error":
|
|
322
|
-
case "network":
|
|
323
|
-
case "provider_unreachable":
|
|
324
|
-
return true;
|
|
325
|
-
default:
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
336
|
+
function isTransientError(err) {
|
|
337
|
+
return err instanceof TheokitAgentError && err.isRetryable === true;
|
|
328
338
|
}
|
|
329
339
|
var KNOWN_AGENT_RUN_ERROR_CODES, TheokitAgentError, AuthenticationError, RateLimitError, ConfigurationError, IntegrationNotConnectedError, NetworkError, UnknownAgentError, AgentRunError, UnsupportedRunOperationError, CredentialPoolExhaustedError, MemoryAdapterError, InvalidTaskIdError, TaskNotFoundError, UnsupportedTaskOperationError, BudgetExceededError, AgentDisposedError, UnsupportedBudgetOperationError;
|
|
330
340
|
var init_errors = __esm({
|
|
331
341
|
"src/errors.ts"() {
|
|
342
|
+
init_default_retriable();
|
|
332
343
|
init_redact();
|
|
333
344
|
KNOWN_AGENT_RUN_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
334
345
|
"rate_limit",
|
|
@@ -1027,6 +1038,19 @@ function sanitizeIdentifier(input, options) {
|
|
|
1027
1038
|
}
|
|
1028
1039
|
return input.toLowerCase();
|
|
1029
1040
|
}
|
|
1041
|
+
function safeFilenameForId(id, options) {
|
|
1042
|
+
if (id.length === 0) {
|
|
1043
|
+
throw new ConfigurationError("Filename id must be a non-empty string", {
|
|
1044
|
+
code: "invalid_filename_id"
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
const maxLen = options?.maxLen;
|
|
1048
|
+
const lower = id.toLowerCase();
|
|
1049
|
+
if (lower.length <= maxLen && IDENTIFIER_PATTERN.test(lower)) {
|
|
1050
|
+
return lower;
|
|
1051
|
+
}
|
|
1052
|
+
return `h-${crypto.createHash("sha256").update(id).digest("hex").slice(0, 16)}`;
|
|
1053
|
+
}
|
|
1030
1054
|
var PathTraversalError, IDENTIFIER_PATTERN;
|
|
1031
1055
|
var init_path_guard = __esm({
|
|
1032
1056
|
"src/internal/security/path-guard.ts"() {
|
|
@@ -2289,6 +2313,11 @@ function makeNotifier() {
|
|
|
2289
2313
|
});
|
|
2290
2314
|
return { promise, resolve: resolve3 };
|
|
2291
2315
|
}
|
|
2316
|
+
function applyScriptMetrics(base, script) {
|
|
2317
|
+
if (script.usage !== void 0) base.usage = script.usage;
|
|
2318
|
+
if (script.cost !== void 0) base.cost = script.cost;
|
|
2319
|
+
if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
|
|
2320
|
+
}
|
|
2292
2321
|
var FixtureRunBase;
|
|
2293
2322
|
var init_fixture_run_base = __esm({
|
|
2294
2323
|
"src/internal/runtime/fixtures/fixture-run-base.ts"() {
|
|
@@ -2395,8 +2424,7 @@ var init_fixture_run_base = __esm({
|
|
|
2395
2424
|
if (status === "error" && this.script.errorDetail !== void 0) {
|
|
2396
2425
|
base.error = this.script.errorDetail;
|
|
2397
2426
|
}
|
|
2398
|
-
|
|
2399
|
-
if (this.script.cost !== void 0) base.cost = this.script.cost;
|
|
2427
|
+
applyScriptMetrics(base, this.script);
|
|
2400
2428
|
return this.extendRunResult(applyExtraRunFields(base, this.script));
|
|
2401
2429
|
}
|
|
2402
2430
|
/** Subclasses override to attach runtime-specific fields (e.g. cloud git info). */
|
|
@@ -4243,10 +4271,7 @@ function sessionsDir(cwd) {
|
|
|
4243
4271
|
return path.join(memoryDir(cwd), "sessions");
|
|
4244
4272
|
}
|
|
4245
4273
|
function sessionSummaryPath(cwd, runId) {
|
|
4246
|
-
return path.join(sessionsDir(cwd), `${
|
|
4247
|
-
}
|
|
4248
|
-
function sanitizeRunId(runId) {
|
|
4249
|
-
return runId.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 128);
|
|
4274
|
+
return path.join(sessionsDir(cwd), `${safeFilenameForId(runId, { maxLen: 128 })}.md`);
|
|
4250
4275
|
}
|
|
4251
4276
|
function truncate(text) {
|
|
4252
4277
|
if (text.length <= MAX_TURN_CHARS) return text;
|
|
@@ -4282,6 +4307,7 @@ var MAX_TURN_CHARS;
|
|
|
4282
4307
|
var init_session_summary_writer = __esm({
|
|
4283
4308
|
"src/internal/memory/storage/session-summary-writer.ts"() {
|
|
4284
4309
|
init_atomic_write();
|
|
4310
|
+
init_path_guard();
|
|
4285
4311
|
init_types();
|
|
4286
4312
|
init_markdown_store();
|
|
4287
4313
|
MAX_TURN_CHARS = 2e3;
|
|
@@ -7112,6 +7138,75 @@ var init_async_local_storage = __esm({
|
|
|
7112
7138
|
}
|
|
7113
7139
|
});
|
|
7114
7140
|
|
|
7141
|
+
// src/internal/runtime/concurrency/async-semaphore.ts
|
|
7142
|
+
function createSemaphore(permits) {
|
|
7143
|
+
if (!Number.isInteger(permits) || permits < 1) {
|
|
7144
|
+
throw new ConfigurationError(
|
|
7145
|
+
`async-semaphore: permits must be a positive integer, got ${permits}`,
|
|
7146
|
+
{ code: "invalid_concurrency" }
|
|
7147
|
+
);
|
|
7148
|
+
}
|
|
7149
|
+
let active = 0;
|
|
7150
|
+
const queue = [];
|
|
7151
|
+
function tryGrant() {
|
|
7152
|
+
if (active < permits && queue.length > 0) {
|
|
7153
|
+
const resolve3 = queue.shift();
|
|
7154
|
+
if (resolve3 !== void 0) {
|
|
7155
|
+
active += 1;
|
|
7156
|
+
resolve3();
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
return {
|
|
7161
|
+
inFlight: () => active,
|
|
7162
|
+
pending: () => queue.length + active,
|
|
7163
|
+
async acquire() {
|
|
7164
|
+
await new Promise((resolve3) => {
|
|
7165
|
+
queue.push(resolve3);
|
|
7166
|
+
tryGrant();
|
|
7167
|
+
});
|
|
7168
|
+
let released = false;
|
|
7169
|
+
return () => {
|
|
7170
|
+
if (released) return;
|
|
7171
|
+
released = true;
|
|
7172
|
+
active -= 1;
|
|
7173
|
+
tryGrant();
|
|
7174
|
+
};
|
|
7175
|
+
}
|
|
7176
|
+
};
|
|
7177
|
+
}
|
|
7178
|
+
var init_async_semaphore = __esm({
|
|
7179
|
+
"src/internal/runtime/concurrency/async-semaphore.ts"() {
|
|
7180
|
+
init_errors();
|
|
7181
|
+
}
|
|
7182
|
+
});
|
|
7183
|
+
|
|
7184
|
+
// src/internal/runtime/concurrency/map-with-concurrency.ts
|
|
7185
|
+
async function mapWithConcurrency(items, concurrency, fn, options) {
|
|
7186
|
+
const semaphore = createSemaphore(concurrency);
|
|
7187
|
+
const signal = NEVER_ABORT;
|
|
7188
|
+
return Promise.all(
|
|
7189
|
+
items.map(async (item, index) => {
|
|
7190
|
+
const release = await semaphore.acquire();
|
|
7191
|
+
try {
|
|
7192
|
+
if (signal.aborted) {
|
|
7193
|
+
throw signal.reason instanceof Error ? signal.reason : new Error("mapWithConcurrency: aborted");
|
|
7194
|
+
}
|
|
7195
|
+
return await fn(item, index, signal);
|
|
7196
|
+
} finally {
|
|
7197
|
+
release();
|
|
7198
|
+
}
|
|
7199
|
+
})
|
|
7200
|
+
);
|
|
7201
|
+
}
|
|
7202
|
+
var NEVER_ABORT;
|
|
7203
|
+
var init_map_with_concurrency = __esm({
|
|
7204
|
+
"src/internal/runtime/concurrency/map-with-concurrency.ts"() {
|
|
7205
|
+
init_async_semaphore();
|
|
7206
|
+
NEVER_ABORT = new AbortController().signal;
|
|
7207
|
+
}
|
|
7208
|
+
});
|
|
7209
|
+
|
|
7115
7210
|
// src/internal/tool-dispatch/repair-middleware.ts
|
|
7116
7211
|
function repairToolCall(raw, registry) {
|
|
7117
7212
|
const repairs = [];
|
|
@@ -7301,38 +7396,12 @@ var init_tool_executors = __esm({
|
|
|
7301
7396
|
// src/internal/agent-loop/tool-dispatch.ts
|
|
7302
7397
|
async function dispatchTools(inputs, tools, toolCalls, events) {
|
|
7303
7398
|
const maxConcurrent = inputs.maxConcurrentTools ?? 4;
|
|
7304
|
-
return
|
|
7305
|
-
maxConcurrent,
|
|
7399
|
+
return mapWithConcurrency(
|
|
7306
7400
|
toolCalls,
|
|
7401
|
+
maxConcurrent,
|
|
7307
7402
|
(call) => dispatchSingleCall(inputs, tools, call, events)
|
|
7308
7403
|
);
|
|
7309
7404
|
}
|
|
7310
|
-
async function boundedParallel(max, items, fn) {
|
|
7311
|
-
let running = 0;
|
|
7312
|
-
const queue = [];
|
|
7313
|
-
async function acquire() {
|
|
7314
|
-
if (running < max) {
|
|
7315
|
-
running++;
|
|
7316
|
-
return;
|
|
7317
|
-
}
|
|
7318
|
-
await new Promise((resolve3) => queue.push(resolve3));
|
|
7319
|
-
running++;
|
|
7320
|
-
}
|
|
7321
|
-
function release() {
|
|
7322
|
-
running--;
|
|
7323
|
-
if (queue.length > 0) queue.shift()();
|
|
7324
|
-
}
|
|
7325
|
-
return Promise.all(
|
|
7326
|
-
items.map(async (item) => {
|
|
7327
|
-
await acquire();
|
|
7328
|
-
try {
|
|
7329
|
-
return await fn(item);
|
|
7330
|
-
} finally {
|
|
7331
|
-
release();
|
|
7332
|
-
}
|
|
7333
|
-
})
|
|
7334
|
-
);
|
|
7335
|
-
}
|
|
7336
7405
|
async function dispatchSingleCall(inputs, tools, call, events) {
|
|
7337
7406
|
const { call: workingCall, repairs } = applyRepairAndExtractCall(tools, call);
|
|
7338
7407
|
const callId = generateCallId();
|
|
@@ -7556,6 +7625,7 @@ var init_tool_dispatch = __esm({
|
|
|
7556
7625
|
"src/internal/agent-loop/tool-dispatch.ts"() {
|
|
7557
7626
|
init_ids();
|
|
7558
7627
|
init_async_local_storage();
|
|
7628
|
+
init_map_with_concurrency();
|
|
7559
7629
|
init_repair_middleware();
|
|
7560
7630
|
init_tool_executors();
|
|
7561
7631
|
}
|
|
@@ -7942,6 +8012,7 @@ async function runAgentLoop(inputs) {
|
|
|
7942
8012
|
const ctx = await initLoopContext(inputs);
|
|
7943
8013
|
ctxRef = ctx;
|
|
7944
8014
|
const budget = inputs.budget ?? new IterationBudget({ maxIterations: inputs.maxIterations ?? 8 });
|
|
8015
|
+
let lastTurnDecision;
|
|
7945
8016
|
while (budget.shouldContinue()) {
|
|
7946
8017
|
if (inputs.budgetTracker !== void 0) {
|
|
7947
8018
|
const decision2 = evaluateBudgetGate(inputs.budgetTracker);
|
|
@@ -7950,18 +8021,26 @@ async function runAgentLoop(inputs) {
|
|
|
7950
8021
|
if (decision2.detail !== void 0) {
|
|
7951
8022
|
ctx.error = { message: decision2.detail, code: decision2.reason ?? "budget" };
|
|
7952
8023
|
}
|
|
8024
|
+
if (decision2.reason === "iteration_limit") {
|
|
8025
|
+
ctx.stoppedAtIterationLimit = true;
|
|
8026
|
+
}
|
|
7953
8027
|
break;
|
|
7954
8028
|
}
|
|
7955
8029
|
}
|
|
7956
8030
|
const usingGrace = budget.remaining <= 0 && !budget.graceCallUsed;
|
|
7957
8031
|
if (usingGrace) budget.useGraceCall();
|
|
7958
8032
|
const decision = await runIteration(inputs, ctx);
|
|
8033
|
+
lastTurnDecision = decision;
|
|
7959
8034
|
if (decision === "done") break;
|
|
7960
8035
|
if (decision === "error") {
|
|
7961
8036
|
ctx.finalStatus = "error";
|
|
7962
8037
|
break;
|
|
7963
8038
|
}
|
|
7964
8039
|
budget.consume();
|
|
8040
|
+
inputs.budgetTracker?.nextIteration?.();
|
|
8041
|
+
}
|
|
8042
|
+
if (lastTurnDecision === "continue" && budget.shouldContinue() === false) {
|
|
8043
|
+
ctx.stoppedAtIterationLimit = true;
|
|
7965
8044
|
}
|
|
7966
8045
|
if (budget.shouldContinue() === false && ctx.finalStatus === "finished" && ctx.finalText === "") {
|
|
7967
8046
|
ctx.finalStatus = "error";
|
|
@@ -7992,7 +8071,8 @@ async function runAgentLoop(inputs) {
|
|
|
7992
8071
|
conversation: ctx.conversation,
|
|
7993
8072
|
...usage !== void 0 ? { usage } : {},
|
|
7994
8073
|
...cost !== void 0 ? { cost } : {},
|
|
7995
|
-
...ctx.error !== void 0 ? { error: ctx.error } : {}
|
|
8074
|
+
...ctx.error !== void 0 ? { error: ctx.error } : {},
|
|
8075
|
+
...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {}
|
|
7996
8076
|
};
|
|
7997
8077
|
} finally {
|
|
7998
8078
|
if (ctxRef !== void 0 && ctxRef.memoryProviderHandle !== void 0 && inputs.memoryProvider !== void 0) {
|
|
@@ -10827,6 +10907,21 @@ var init_client = __esm({
|
|
|
10827
10907
|
}
|
|
10828
10908
|
});
|
|
10829
10909
|
|
|
10910
|
+
// src/internal/providers/register-plugin-providers.ts
|
|
10911
|
+
function registerPluginProviderProfiles(entries) {
|
|
10912
|
+
let registered4 = 0;
|
|
10913
|
+
for (const entry of entries) {
|
|
10914
|
+
registerProvider(entry.profile);
|
|
10915
|
+
registered4 += 1;
|
|
10916
|
+
}
|
|
10917
|
+
return registered4;
|
|
10918
|
+
}
|
|
10919
|
+
var init_register_plugin_providers = __esm({
|
|
10920
|
+
"src/internal/providers/register-plugin-providers.ts"() {
|
|
10921
|
+
init_registry();
|
|
10922
|
+
}
|
|
10923
|
+
});
|
|
10924
|
+
|
|
10830
10925
|
// src/internal/tool-registry/personality-filter.ts
|
|
10831
10926
|
function applyPersonalityFilter(exposedTools, whitelist, opts) {
|
|
10832
10927
|
if (whitelist === void 0) return exposedTools;
|
|
@@ -10907,12 +11002,33 @@ function createRealLocalRun(options) {
|
|
|
10907
11002
|
registerRun(handle);
|
|
10908
11003
|
return handle;
|
|
10909
11004
|
}
|
|
10910
|
-
function
|
|
11005
|
+
function resolveRunProvider(options) {
|
|
10911
11006
|
registerBuiltins();
|
|
11007
|
+
const profiles = options.pluginManager?.aggregated.providerProfiles ?? [];
|
|
11008
|
+
const registered4 = registerPluginProviderProfiles(profiles);
|
|
11009
|
+
if (registered4 > 0 && !pluginProvidersAnnounced) {
|
|
11010
|
+
pluginProvidersAnnounced = true;
|
|
11011
|
+
const names = profiles.map((e) => e.profile.name).join(", ");
|
|
11012
|
+
process.stderr.write(
|
|
11013
|
+
`[theokit-sdk] registered ${registered4} plugin provider profile(s): ${names}
|
|
11014
|
+
`
|
|
11015
|
+
);
|
|
11016
|
+
}
|
|
10912
11017
|
const parsedModel = parseModelId(options.model?.id);
|
|
10913
11018
|
const inferredProvider = parsedModel.provider !== void 0 && getProviderProfile(parsedModel.provider) !== void 0 ? parsedModel.provider : void 0;
|
|
10914
11019
|
const primary = options.agentOptions.providers?.routes?.[0]?.provider ?? inferredProvider ?? detectPrimaryProvider();
|
|
10915
11020
|
const effectiveModelId = inferredProvider !== void 0 ? parsedModel.name : options.model?.id ?? "claude-sonnet-4-6";
|
|
11021
|
+
return { primary, effectiveModelId };
|
|
11022
|
+
}
|
|
11023
|
+
function buildLoopInputs(options, runId, userText) {
|
|
11024
|
+
const maxIterations = options.sendOptions.maxIterations;
|
|
11025
|
+
if (maxIterations !== void 0 && (!Number.isInteger(maxIterations) || maxIterations < 1)) {
|
|
11026
|
+
throw new ConfigurationError(
|
|
11027
|
+
`SendOptions.maxIterations must be a positive integer, got ${maxIterations}`,
|
|
11028
|
+
{ code: "invalid_max_iterations" }
|
|
11029
|
+
);
|
|
11030
|
+
}
|
|
11031
|
+
const { primary, effectiveModelId } = resolveRunProvider(options);
|
|
10916
11032
|
const fallback = options.agentOptions.providers?.fallback;
|
|
10917
11033
|
const apiKeys = options.agentOptions.providers?.apiKeys;
|
|
10918
11034
|
const credentialPoolStrategy = options.agentOptions.providers?.credentialPoolStrategy;
|
|
@@ -10950,6 +11066,9 @@ function buildLoopInputs(options, runId, userText) {
|
|
|
10950
11066
|
// D318 — forward SendOptions.signal to the agent loop so streamLlmTurn
|
|
10951
11067
|
// can attach it to the LLM `fetch({ signal })` call.
|
|
10952
11068
|
...options.sendOptions.signal !== void 0 ? { signal: options.sendOptions.signal } : {},
|
|
11069
|
+
// M1-2: per-send iteration ceiling (validated above). The loop reads
|
|
11070
|
+
// inputs.maxIterations (default 8 when unset).
|
|
11071
|
+
...maxIterations !== void 0 ? { maxIterations } : {},
|
|
10953
11072
|
// D315-D317 — tool lifecycle hooks (cost tracking + audit + retry/alert)
|
|
10954
11073
|
...options.agentOptions.onToolStart !== void 0 ? { onToolStart: options.agentOptions.onToolStart } : {},
|
|
10955
11074
|
...options.agentOptions.onToolEnd !== void 0 ? { onToolEnd: options.agentOptions.onToolEnd } : {},
|
|
@@ -11006,19 +11125,22 @@ function buildMcpMap(options) {
|
|
|
11006
11125
|
}
|
|
11007
11126
|
return map;
|
|
11008
11127
|
}
|
|
11009
|
-
var RealLocalRun;
|
|
11128
|
+
var pluginProvidersAnnounced, RealLocalRun;
|
|
11010
11129
|
var init_real_local_run = __esm({
|
|
11011
11130
|
"src/internal/runtime/local-agent/real-local-run.ts"() {
|
|
11131
|
+
init_errors();
|
|
11012
11132
|
init_loop();
|
|
11013
11133
|
init_fallback_client();
|
|
11014
11134
|
init_model_identifier();
|
|
11015
11135
|
init_router();
|
|
11016
11136
|
init_client();
|
|
11017
11137
|
init_providers();
|
|
11138
|
+
init_register_plugin_providers();
|
|
11018
11139
|
init_tracer();
|
|
11019
11140
|
init_personality_filter();
|
|
11020
11141
|
init_fixture_run_base();
|
|
11021
11142
|
init_run_registry();
|
|
11143
|
+
pluginProvidersAnnounced = false;
|
|
11022
11144
|
RealLocalRun = class extends FixtureRunBase {
|
|
11023
11145
|
buildInputs;
|
|
11024
11146
|
constructor(options, buildInputs) {
|
|
@@ -11094,6 +11216,7 @@ var init_real_local_run = __esm({
|
|
|
11094
11216
|
if (output.result.length > 0) this.script.result = output.result;
|
|
11095
11217
|
if (output.usage !== void 0) this.script.usage = output.usage;
|
|
11096
11218
|
if (output.cost !== void 0) this.script.cost = output.cost;
|
|
11219
|
+
if (output.stoppedAtIterationLimit === true) this.script.stoppedAtIterationLimit = true;
|
|
11097
11220
|
if (output.error !== void 0 && this.script.errorDetail === void 0) {
|
|
11098
11221
|
this.script.errorDetail = {
|
|
11099
11222
|
message: output.error.message,
|
|
@@ -11570,7 +11693,7 @@ async function embedTexts(input) {
|
|
|
11570
11693
|
pending
|
|
11571
11694
|
});
|
|
11572
11695
|
}
|
|
11573
|
-
await
|
|
11696
|
+
await embedInBoundedBatches(input, pending, results);
|
|
11574
11697
|
return results.map((v) => v ?? new Array(dimension).fill(0));
|
|
11575
11698
|
}
|
|
11576
11699
|
function classifyEntry(args) {
|
|
@@ -11588,45 +11711,34 @@ function classifyEntry(args) {
|
|
|
11588
11711
|
args.stats.cacheMisses += 1;
|
|
11589
11712
|
args.pending.push({ index: args.index, text: args.text, key });
|
|
11590
11713
|
}
|
|
11591
|
-
async function
|
|
11714
|
+
async function embedInBoundedBatches(input, pending, results) {
|
|
11592
11715
|
const batches = [];
|
|
11593
11716
|
for (let offset = 0; offset < pending.length; offset += MAX_BATCH) {
|
|
11594
11717
|
batches.push(pending.slice(offset, offset + MAX_BATCH));
|
|
11595
11718
|
}
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
running++;
|
|
11602
|
-
}
|
|
11603
|
-
function release() {
|
|
11604
|
-
running--;
|
|
11605
|
-
if (queue.length > 0) queue.shift()();
|
|
11606
|
-
}
|
|
11719
|
+
await mapWithConcurrency(
|
|
11720
|
+
batches,
|
|
11721
|
+
MAX_CONCURRENT_BATCHES,
|
|
11722
|
+
(batch) => processBatch(input, batch, results)
|
|
11723
|
+
);
|
|
11607
11724
|
}
|
|
11608
|
-
async function processBatch(input, batch, results
|
|
11609
|
-
await
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
results[slot.index] = vector;
|
|
11626
|
-
input.cache.set(slot.key, vector);
|
|
11627
|
-
}
|
|
11628
|
-
} finally {
|
|
11629
|
-
release();
|
|
11725
|
+
async function processBatch(input, batch, results) {
|
|
11726
|
+
const vectors = await embedBatch({
|
|
11727
|
+
apiKey: input.apiKey,
|
|
11728
|
+
baseUrl: input.baseUrl,
|
|
11729
|
+
embeddingsPath: input.embeddingsPath,
|
|
11730
|
+
model: input.model,
|
|
11731
|
+
inputs: batch.map((b) => b.text),
|
|
11732
|
+
fetchImpl: input.fetchImpl,
|
|
11733
|
+
stats: input.stats,
|
|
11734
|
+
providerId: input.providerId
|
|
11735
|
+
});
|
|
11736
|
+
for (let j = 0; j < batch.length; j++) {
|
|
11737
|
+
const slot = batch[j];
|
|
11738
|
+
const vector = vectors[j];
|
|
11739
|
+
if (slot === void 0 || vector === void 0) continue;
|
|
11740
|
+
results[slot.index] = vector;
|
|
11741
|
+
input.cache.set(slot.key, vector);
|
|
11630
11742
|
}
|
|
11631
11743
|
}
|
|
11632
11744
|
async function embedBatch(opts) {
|
|
@@ -11700,6 +11812,7 @@ var init_openai_compatible2 = __esm({
|
|
|
11700
11812
|
"src/internal/memory/adapters/openai-compatible.ts"() {
|
|
11701
11813
|
init_errors();
|
|
11702
11814
|
init_openai_compatible();
|
|
11815
|
+
init_map_with_concurrency();
|
|
11703
11816
|
init_embedding_cache();
|
|
11704
11817
|
MAX_BATCH = 100;
|
|
11705
11818
|
MAX_RETRIES = 2;
|
|
@@ -12184,6 +12297,61 @@ var init_sqlite_wal = __esm({
|
|
|
12184
12297
|
warnedLabels = /* @__PURE__ */ new Set();
|
|
12185
12298
|
}
|
|
12186
12299
|
});
|
|
12300
|
+
async function openSqliteResilient(options) {
|
|
12301
|
+
await promises.mkdir(path.dirname(options.filePath), { recursive: true });
|
|
12302
|
+
try {
|
|
12303
|
+
return await openConcrete(options);
|
|
12304
|
+
} catch (cause) {
|
|
12305
|
+
if (options.recoverCorrupt !== false && isCorruptionError(cause)) {
|
|
12306
|
+
await renameAside(options.filePath, options.label ?? "sqlite");
|
|
12307
|
+
return await openConcrete(options);
|
|
12308
|
+
}
|
|
12309
|
+
throw cause;
|
|
12310
|
+
}
|
|
12311
|
+
}
|
|
12312
|
+
async function openConcrete(options) {
|
|
12313
|
+
const db = await loadDriver(options.filePath);
|
|
12314
|
+
applyWalWithFallback(db, options.label ?? "sqlite");
|
|
12315
|
+
await options.onOpen?.(db);
|
|
12316
|
+
return db;
|
|
12317
|
+
}
|
|
12318
|
+
async function loadDriver(filePath) {
|
|
12319
|
+
try {
|
|
12320
|
+
const mod = await import('better-sqlite3');
|
|
12321
|
+
const Ctor = mod.default ?? mod;
|
|
12322
|
+
if (typeof Ctor !== "function") {
|
|
12323
|
+
throw new Error(`better-sqlite3 export is not a constructor (got ${typeof Ctor})`);
|
|
12324
|
+
}
|
|
12325
|
+
return new Ctor(filePath);
|
|
12326
|
+
} catch (cause) {
|
|
12327
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
12328
|
+
throw new ConfigurationError(
|
|
12329
|
+
`Failed to load SQLite driver. Install \`better-sqlite3\` or run on Node 22.5+ for built-in \`node:sqlite\`. Cause: ${message}`,
|
|
12330
|
+
{ code: "sqlite_driver_unavailable", cause }
|
|
12331
|
+
);
|
|
12332
|
+
}
|
|
12333
|
+
}
|
|
12334
|
+
function isCorruptionError(cause) {
|
|
12335
|
+
if (!(cause instanceof Error)) return false;
|
|
12336
|
+
const msg = cause.message.toLowerCase();
|
|
12337
|
+
return msg.includes("malformed") || msg.includes("not a database") || msg.includes("encrypted") || msg.includes("disk image is malformed");
|
|
12338
|
+
}
|
|
12339
|
+
async function renameAside(filePath, label) {
|
|
12340
|
+
const asidePath = `${filePath}.corrupt-${Date.now()}`;
|
|
12341
|
+
await promises.rename(filePath, asidePath).catch(() => void 0);
|
|
12342
|
+
await promises.rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => void 0);
|
|
12343
|
+
await promises.rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => void 0);
|
|
12344
|
+
process.stderr.write(
|
|
12345
|
+
`[theokit-sdk] ${label} database corrupt; renamed aside to ${asidePath} and rebuilt schema
|
|
12346
|
+
`
|
|
12347
|
+
);
|
|
12348
|
+
}
|
|
12349
|
+
var init_sqlite_open = __esm({
|
|
12350
|
+
"src/internal/persistence/sqlite-open.ts"() {
|
|
12351
|
+
init_errors();
|
|
12352
|
+
init_sqlite_wal();
|
|
12353
|
+
}
|
|
12354
|
+
});
|
|
12187
12355
|
|
|
12188
12356
|
// src/internal/memory/index-schema.ts
|
|
12189
12357
|
var SCHEMA_STATEMENTS, PRAGMA_STATEMENTS;
|
|
@@ -12231,60 +12399,22 @@ var init_index_schema = __esm({
|
|
|
12231
12399
|
}
|
|
12232
12400
|
});
|
|
12233
12401
|
async function openMemoryDb(opts) {
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
12402
|
+
return openSqliteResilient({
|
|
12403
|
+
filePath: opts.filePath,
|
|
12404
|
+
label: "memory-index",
|
|
12405
|
+
recoverCorrupt: opts.recoverCorrupt,
|
|
12406
|
+
onOpen: (db) => {
|
|
12407
|
+
for (const pragma of PRAGMA_STATEMENTS) db.exec(pragma);
|
|
12408
|
+
for (const stmt of SCHEMA_STATEMENTS) db.exec(stmt);
|
|
12241
12409
|
}
|
|
12242
|
-
|
|
12243
|
-
}
|
|
12244
|
-
}
|
|
12245
|
-
async function openConcrete(filePath) {
|
|
12246
|
-
const db = await loadDriver(filePath);
|
|
12247
|
-
applyWalWithFallback(db, "memory-index");
|
|
12248
|
-
for (const pragma of PRAGMA_STATEMENTS) db.exec(pragma);
|
|
12249
|
-
for (const stmt of SCHEMA_STATEMENTS) db.exec(stmt);
|
|
12250
|
-
return db;
|
|
12251
|
-
}
|
|
12252
|
-
async function loadDriver(filePath) {
|
|
12253
|
-
try {
|
|
12254
|
-
const mod = await import('better-sqlite3');
|
|
12255
|
-
const Ctor = mod.default ?? mod;
|
|
12256
|
-
const db = new Ctor(filePath);
|
|
12257
|
-
return db;
|
|
12258
|
-
} catch (cause) {
|
|
12259
|
-
const message = cause instanceof Error ? cause.message : String(cause);
|
|
12260
|
-
throw new ConfigurationError(
|
|
12261
|
-
`Failed to load SQLite driver. Install \`better-sqlite3\` or run on Node 22.5+ for built-in \`node:sqlite\`. Cause: ${message}`,
|
|
12262
|
-
{ code: "sqlite_driver_unavailable", cause }
|
|
12263
|
-
);
|
|
12264
|
-
}
|
|
12265
|
-
}
|
|
12266
|
-
function isCorruptionError(cause) {
|
|
12267
|
-
if (!(cause instanceof Error)) return false;
|
|
12268
|
-
const msg = cause.message.toLowerCase();
|
|
12269
|
-
return msg.includes("malformed") || msg.includes("not a database") || msg.includes("encrypted") || msg.includes("disk image is malformed");
|
|
12270
|
-
}
|
|
12271
|
-
async function renameAside(filePath) {
|
|
12272
|
-
const asidePath = `${filePath}.corrupt-${Date.now()}`;
|
|
12273
|
-
await promises.rename(filePath, asidePath).catch(() => void 0);
|
|
12274
|
-
await promises.rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => void 0);
|
|
12275
|
-
await promises.rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => void 0);
|
|
12276
|
-
process.stderr.write(
|
|
12277
|
-
`[theokit-sdk] memory index corrupt; renamed aside to ${asidePath} and rebuilt schema
|
|
12278
|
-
`
|
|
12279
|
-
);
|
|
12410
|
+
});
|
|
12280
12411
|
}
|
|
12281
12412
|
function defaultIndexPath(cwd) {
|
|
12282
12413
|
return path.join(cwd, ".theokit", "memory", ".index", "memory.sqlite");
|
|
12283
12414
|
}
|
|
12284
12415
|
var init_index_db = __esm({
|
|
12285
12416
|
"src/internal/memory/index-db.ts"() {
|
|
12286
|
-
|
|
12287
|
-
init_sqlite_wal();
|
|
12417
|
+
init_sqlite_open();
|
|
12288
12418
|
init_index_schema();
|
|
12289
12419
|
}
|
|
12290
12420
|
});
|
|
@@ -14347,49 +14477,6 @@ var init_task = __esm({
|
|
|
14347
14477
|
}
|
|
14348
14478
|
});
|
|
14349
14479
|
|
|
14350
|
-
// src/internal/runtime/concurrency/async-semaphore.ts
|
|
14351
|
-
function createSemaphore(permits) {
|
|
14352
|
-
if (!Number.isInteger(permits) || permits < 1) {
|
|
14353
|
-
throw new ConfigurationError(
|
|
14354
|
-
`async-semaphore: permits must be a positive integer, got ${permits}`,
|
|
14355
|
-
{ code: "invalid_concurrency" }
|
|
14356
|
-
);
|
|
14357
|
-
}
|
|
14358
|
-
let active = 0;
|
|
14359
|
-
const queue = [];
|
|
14360
|
-
function tryGrant() {
|
|
14361
|
-
if (active < permits && queue.length > 0) {
|
|
14362
|
-
const resolve3 = queue.shift();
|
|
14363
|
-
if (resolve3 !== void 0) {
|
|
14364
|
-
active += 1;
|
|
14365
|
-
resolve3();
|
|
14366
|
-
}
|
|
14367
|
-
}
|
|
14368
|
-
}
|
|
14369
|
-
return {
|
|
14370
|
-
inFlight: () => active,
|
|
14371
|
-
pending: () => queue.length + active,
|
|
14372
|
-
async acquire() {
|
|
14373
|
-
await new Promise((resolve3) => {
|
|
14374
|
-
queue.push(resolve3);
|
|
14375
|
-
tryGrant();
|
|
14376
|
-
});
|
|
14377
|
-
let released = false;
|
|
14378
|
-
return () => {
|
|
14379
|
-
if (released) return;
|
|
14380
|
-
released = true;
|
|
14381
|
-
active -= 1;
|
|
14382
|
-
tryGrant();
|
|
14383
|
-
};
|
|
14384
|
-
}
|
|
14385
|
-
};
|
|
14386
|
-
}
|
|
14387
|
-
var init_async_semaphore = __esm({
|
|
14388
|
-
"src/internal/runtime/concurrency/async-semaphore.ts"() {
|
|
14389
|
-
init_errors();
|
|
14390
|
-
}
|
|
14391
|
-
});
|
|
14392
|
-
|
|
14393
14480
|
// src/internal/task/ring-buffer.ts
|
|
14394
14481
|
var RingBuffer;
|
|
14395
14482
|
var init_ring_buffer = __esm({
|