theokit 0.8.0 → 0.8.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.
@@ -2,11 +2,11 @@
2
2
  import "tsx/esm";
3
3
  import "./chunk-KT3MWNZG.js";
4
4
 
5
- // ../../node_modules/.pnpm/@theokit+sdk@2.0.1_@lancedb+lancedb@0.30.0_apache-arrow@18.1.0__@types+ws@8.18.1_better-sqlit_hxks36aepiyjbgw5nq4izwbfgy/node_modules/@theokit/sdk/dist/index.js
5
+ // ../../node_modules/.pnpm/@theokit+sdk@2.5.0_@lancedb+lancedb@0.30.0_apache-arrow@18.1.0__@types+ws@8.18.1_better-sqlit_zipxufn4zgvf3bcwwyuqnkcqfi/node_modules/@theokit/sdk/dist/index.js
6
+ import { createHash, randomUUID, randomBytes } from "crypto";
6
7
  import { existsSync, rmSync, mkdirSync, renameSync, readFileSync, realpathSync, lstatSync, readlinkSync, readdirSync } from "fs";
7
8
  import { join, dirname, relative, resolve, sep, isAbsolute } from "path";
8
- import { createHash, randomUUID, randomBytes } from "crypto";
9
- import { readFile, stat, rm, readdir, mkdir, appendFile, rename, open, unlink, statfs, access } from "fs/promises";
9
+ import { readFile, stat, rm, readdir, mkdir, appendFile, open, rename, unlink, statfs, access } from "fs/promises";
10
10
  import { z, toJSONSchema } from "zod";
11
11
  import { AsyncLocalStorage } from "async_hooks";
12
12
  import { createRequire } from "module";
@@ -384,7 +384,7 @@ var R = class {
384
384
  }
385
385
  };
386
386
 
387
- // ../../node_modules/.pnpm/@theokit+sdk@2.0.1_@lancedb+lancedb@0.30.0_apache-arrow@18.1.0__@types+ws@8.18.1_better-sqlit_hxks36aepiyjbgw5nq4izwbfgy/node_modules/@theokit/sdk/dist/index.js
387
+ // ../../node_modules/.pnpm/@theokit+sdk@2.5.0_@lancedb+lancedb@0.30.0_apache-arrow@18.1.0__@types+ws@8.18.1_better-sqlit_zipxufn4zgvf3bcwwyuqnkcqfi/node_modules/@theokit/sdk/dist/index.js
388
388
  var __defProp = Object.defineProperty;
389
389
  var __getOwnPropNames = Object.getOwnPropertyNames;
390
390
  var __esm = (fn, res) => function __init() {
@@ -394,6 +394,22 @@ var __export = (target, all) => {
394
394
  for (var name in all)
395
395
  __defProp(target, name, { get: all[name], enumerable: true });
396
396
  };
397
+ function defaultRetriableForCode(code) {
398
+ switch (code) {
399
+ case "rate_limit":
400
+ case "timeout":
401
+ case "server_error":
402
+ case "network":
403
+ case "provider_unreachable":
404
+ return true;
405
+ default:
406
+ return false;
407
+ }
408
+ }
409
+ var init_default_retriable = __esm({
410
+ "src/internal/default-retriable.ts"() {
411
+ }
412
+ });
397
413
  function readEnvOnce() {
398
414
  const raw = process.env.THEOKIT_REDACT_SECRETS;
399
415
  if (raw === void 0) return true;
@@ -552,7 +568,8 @@ __export(errors_exports, {
552
568
  UnsupportedBudgetOperationError: () => UnsupportedBudgetOperationError,
553
569
  UnsupportedRunOperationError: () => UnsupportedRunOperationError,
554
570
  UnsupportedTaskOperationError: () => UnsupportedTaskOperationError,
555
- coerceToKnownAgentRunErrorCode: () => coerceToKnownAgentRunErrorCode
571
+ coerceToKnownAgentRunErrorCode: () => coerceToKnownAgentRunErrorCode,
572
+ isTransientError: () => isTransientError
556
573
  });
557
574
  function coerceToKnownAgentRunErrorCode(code) {
558
575
  if (code !== void 0 && KNOWN_AGENT_RUN_ERROR_CODES.has(code)) {
@@ -584,17 +601,8 @@ function safeStringify(value) {
584
601
  return String(value);
585
602
  }
586
603
  }
587
- function defaultRetriableForCode(code) {
588
- switch (code) {
589
- case "rate_limit":
590
- case "timeout":
591
- case "server_error":
592
- case "network":
593
- case "provider_unreachable":
594
- return true;
595
- default:
596
- return false;
597
- }
604
+ function isTransientError(err) {
605
+ return err instanceof TheokitAgentError && err.isRetryable === true;
598
606
  }
599
607
  var KNOWN_AGENT_RUN_ERROR_CODES;
600
608
  var TheokitAgentError;
@@ -616,6 +624,7 @@ var AgentDisposedError;
616
624
  var UnsupportedBudgetOperationError;
617
625
  var init_errors = __esm({
618
626
  "src/errors.ts"() {
627
+ init_default_retriable();
619
628
  init_redact();
620
629
  KNOWN_AGENT_RUN_ERROR_CODES = /* @__PURE__ */ new Set([
621
630
  "rate_limit",
@@ -1037,6 +1046,19 @@ function sanitizeIdentifier(input, options) {
1037
1046
  }
1038
1047
  return input.toLowerCase();
1039
1048
  }
1049
+ function safeFilenameForId(id, options) {
1050
+ if (id.length === 0) {
1051
+ throw new ConfigurationError("Filename id must be a non-empty string", {
1052
+ code: "invalid_filename_id"
1053
+ });
1054
+ }
1055
+ const maxLen = options?.maxLen;
1056
+ const lower = id.toLowerCase();
1057
+ if (lower.length <= maxLen && IDENTIFIER_PATTERN.test(lower)) {
1058
+ return lower;
1059
+ }
1060
+ return `h-${createHash("sha256").update(id).digest("hex").slice(0, 16)}`;
1061
+ }
1040
1062
  var PathTraversalError;
1041
1063
  var IDENTIFIER_PATTERN;
1042
1064
  var init_path_guard = __esm({
@@ -1439,10 +1461,7 @@ function sessionsDir(cwd) {
1439
1461
  return join(memoryDir(cwd), "sessions");
1440
1462
  }
1441
1463
  function sessionSummaryPath(cwd, runId) {
1442
- return join(sessionsDir(cwd), `${sanitizeRunId(runId)}.md`);
1443
- }
1444
- function sanitizeRunId(runId) {
1445
- return runId.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 128);
1464
+ return join(sessionsDir(cwd), `${safeFilenameForId(runId, { maxLen: 128 })}.md`);
1446
1465
  }
1447
1466
  function truncate(text) {
1448
1467
  if (text.length <= MAX_TURN_CHARS) return text;
@@ -1478,6 +1497,7 @@ var MAX_TURN_CHARS;
1478
1497
  var init_session_summary_writer = __esm({
1479
1498
  "src/internal/memory/storage/session-summary-writer.ts"() {
1480
1499
  init_atomic_write();
1500
+ init_path_guard();
1481
1501
  init_types();
1482
1502
  init_markdown_store();
1483
1503
  MAX_TURN_CHARS = 2e3;
@@ -1506,6 +1526,47 @@ var init_async_local_storage = __esm({
1506
1526
  toolWhitelistStore = new AsyncLocalStorage();
1507
1527
  }
1508
1528
  });
1529
+ function createSemaphore(permits) {
1530
+ if (!Number.isInteger(permits) || permits < 1) {
1531
+ throw new ConfigurationError(
1532
+ `async-semaphore: permits must be a positive integer, got ${permits}`,
1533
+ { code: "invalid_concurrency" }
1534
+ );
1535
+ }
1536
+ let active = 0;
1537
+ const queue = [];
1538
+ function tryGrant() {
1539
+ if (active < permits && queue.length > 0) {
1540
+ const resolve3 = queue.shift();
1541
+ if (resolve3 !== void 0) {
1542
+ active += 1;
1543
+ resolve3();
1544
+ }
1545
+ }
1546
+ }
1547
+ return {
1548
+ inFlight: () => active,
1549
+ pending: () => queue.length + active,
1550
+ async acquire() {
1551
+ await new Promise((resolve3) => {
1552
+ queue.push(resolve3);
1553
+ tryGrant();
1554
+ });
1555
+ let released = false;
1556
+ return () => {
1557
+ if (released) return;
1558
+ released = true;
1559
+ active -= 1;
1560
+ tryGrant();
1561
+ };
1562
+ }
1563
+ };
1564
+ }
1565
+ var init_async_semaphore = __esm({
1566
+ "src/internal/runtime/concurrency/async-semaphore.ts"() {
1567
+ init_errors();
1568
+ }
1569
+ });
1509
1570
  var COOLDOWN_MS;
1510
1571
  var DEFAULT_COOLDOWN_MS;
1511
1572
  var init_credential_pool_types = __esm({
@@ -1879,6 +1940,61 @@ var init_sqlite_wal = __esm({
1879
1940
  warnedLabels = /* @__PURE__ */ new Set();
1880
1941
  }
1881
1942
  });
1943
+ async function openSqliteResilient(options) {
1944
+ await mkdir(dirname(options.filePath), { recursive: true });
1945
+ try {
1946
+ return await openConcrete(options);
1947
+ } catch (cause) {
1948
+ if (options.recoverCorrupt !== false && isCorruptionError(cause)) {
1949
+ await renameAside(options.filePath, options.label ?? "sqlite");
1950
+ return await openConcrete(options);
1951
+ }
1952
+ throw cause;
1953
+ }
1954
+ }
1955
+ async function openConcrete(options) {
1956
+ const db = await loadDriver(options.filePath);
1957
+ applyWalWithFallback(db, options.label ?? "sqlite");
1958
+ await options.onOpen?.(db);
1959
+ return db;
1960
+ }
1961
+ async function loadDriver(filePath) {
1962
+ try {
1963
+ const mod = await import("./lib-JBI3XXH3.js");
1964
+ const Ctor = mod.default ?? mod;
1965
+ if (typeof Ctor !== "function") {
1966
+ throw new Error(`better-sqlite3 export is not a constructor (got ${typeof Ctor})`);
1967
+ }
1968
+ return new Ctor(filePath);
1969
+ } catch (cause) {
1970
+ const message = cause instanceof Error ? cause.message : String(cause);
1971
+ throw new ConfigurationError(
1972
+ `Failed to load SQLite driver. Install \`better-sqlite3\` or run on Node 22.5+ for built-in \`node:sqlite\`. Cause: ${message}`,
1973
+ { code: "sqlite_driver_unavailable", cause }
1974
+ );
1975
+ }
1976
+ }
1977
+ function isCorruptionError(cause) {
1978
+ if (!(cause instanceof Error)) return false;
1979
+ const msg = cause.message.toLowerCase();
1980
+ return msg.includes("malformed") || msg.includes("not a database") || msg.includes("encrypted") || msg.includes("disk image is malformed");
1981
+ }
1982
+ async function renameAside(filePath, label) {
1983
+ const asidePath = `${filePath}.corrupt-${Date.now()}`;
1984
+ await rename(filePath, asidePath).catch(() => void 0);
1985
+ await rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => void 0);
1986
+ await rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => void 0);
1987
+ process.stderr.write(
1988
+ `[theokit-sdk] ${label} database corrupt; renamed aside to ${asidePath} and rebuilt schema
1989
+ `
1990
+ );
1991
+ }
1992
+ var init_sqlite_open = __esm({
1993
+ "src/internal/persistence/sqlite-open.ts"() {
1994
+ init_errors();
1995
+ init_sqlite_wal();
1996
+ }
1997
+ });
1882
1998
  var SCHEMA_STATEMENTS;
1883
1999
  var PRAGMA_STATEMENTS;
1884
2000
  var init_index_schema = __esm({
@@ -1925,60 +2041,22 @@ var init_index_schema = __esm({
1925
2041
  }
1926
2042
  });
1927
2043
  async function openMemoryDb(opts) {
1928
- await mkdir(dirname(opts.filePath), { recursive: true });
1929
- try {
1930
- return await openConcrete(opts.filePath);
1931
- } catch (cause) {
1932
- if (opts.recoverCorrupt !== false && isCorruptionError(cause)) {
1933
- await renameAside(opts.filePath);
1934
- return await openConcrete(opts.filePath);
2044
+ return openSqliteResilient({
2045
+ filePath: opts.filePath,
2046
+ label: "memory-index",
2047
+ recoverCorrupt: opts.recoverCorrupt,
2048
+ onOpen: (db) => {
2049
+ for (const pragma of PRAGMA_STATEMENTS) db.exec(pragma);
2050
+ for (const stmt of SCHEMA_STATEMENTS) db.exec(stmt);
1935
2051
  }
1936
- throw cause;
1937
- }
1938
- }
1939
- async function openConcrete(filePath) {
1940
- const db = await loadDriver(filePath);
1941
- applyWalWithFallback(db, "memory-index");
1942
- for (const pragma of PRAGMA_STATEMENTS) db.exec(pragma);
1943
- for (const stmt of SCHEMA_STATEMENTS) db.exec(stmt);
1944
- return db;
1945
- }
1946
- async function loadDriver(filePath) {
1947
- try {
1948
- const mod = await import("./lib-JBI3XXH3.js");
1949
- const Ctor = mod.default ?? mod;
1950
- const db = new Ctor(filePath);
1951
- return db;
1952
- } catch (cause) {
1953
- const message = cause instanceof Error ? cause.message : String(cause);
1954
- throw new ConfigurationError(
1955
- `Failed to load SQLite driver. Install \`better-sqlite3\` or run on Node 22.5+ for built-in \`node:sqlite\`. Cause: ${message}`,
1956
- { code: "sqlite_driver_unavailable", cause }
1957
- );
1958
- }
1959
- }
1960
- function isCorruptionError(cause) {
1961
- if (!(cause instanceof Error)) return false;
1962
- const msg = cause.message.toLowerCase();
1963
- return msg.includes("malformed") || msg.includes("not a database") || msg.includes("encrypted") || msg.includes("disk image is malformed");
1964
- }
1965
- async function renameAside(filePath) {
1966
- const asidePath = `${filePath}.corrupt-${Date.now()}`;
1967
- await rename(filePath, asidePath).catch(() => void 0);
1968
- await rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => void 0);
1969
- await rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => void 0);
1970
- process.stderr.write(
1971
- `[theokit-sdk] memory index corrupt; renamed aside to ${asidePath} and rebuilt schema
1972
- `
1973
- );
2052
+ });
1974
2053
  }
1975
2054
  function defaultIndexPath(cwd) {
1976
2055
  return join(cwd, ".theokit", "memory", ".index", "memory.sqlite");
1977
2056
  }
1978
2057
  var init_index_db = __esm({
1979
2058
  "src/internal/memory/index-db.ts"() {
1980
- init_errors();
1981
- init_sqlite_wal();
2059
+ init_sqlite_open();
1982
2060
  init_index_schema();
1983
2061
  }
1984
2062
  });
@@ -3077,6 +3155,70 @@ var init_agent_factory_registry = __esm({
3077
3155
  "src/internal/runtime/registry/agent-factory-registry.ts"() {
3078
3156
  }
3079
3157
  });
3158
+ var run_to_completion_exports = {};
3159
+ __export(run_to_completion_exports, {
3160
+ classifyRound: () => classifyRound,
3161
+ runToCompletionImpl: () => runToCompletionImpl
3162
+ });
3163
+ function isEmptyRound(result) {
3164
+ return (result.result ?? "").trim() === "";
3165
+ }
3166
+ function classifyRound(result, round, maxRounds, emptyStreak) {
3167
+ if (result.stoppedAtIterationLimit !== true) return "done";
3168
+ if (isEmptyRound(result) && emptyStreak >= 1) return "no_progress";
3169
+ if (round >= maxRounds) return "step_limit";
3170
+ return "continue";
3171
+ }
3172
+ function addUsage(acc, u) {
3173
+ if (u === void 0) return acc;
3174
+ const inputTokens = (acc?.inputTokens ?? 0) + u.inputTokens;
3175
+ const outputTokens = (acc?.outputTokens ?? 0) + u.outputTokens;
3176
+ const sumOpt = (a, b2) => a === void 0 && b2 === void 0 ? void 0 : (a ?? 0) + (b2 ?? 0);
3177
+ return {
3178
+ inputTokens,
3179
+ outputTokens,
3180
+ totalTokens: inputTokens + outputTokens,
3181
+ cacheReadTokens: sumOpt(acc?.cacheReadTokens, u.cacheReadTokens),
3182
+ cacheWriteTokens: sumOpt(acc?.cacheWriteTokens, u.cacheWriteTokens),
3183
+ reasoningTokens: sumOpt(acc?.reasoningTokens, u.reasoningTokens)
3184
+ };
3185
+ }
3186
+ function buildResult(terminal, rounds, lastResult, usage) {
3187
+ return { terminal, rounds, lastResult, ...usage !== void 0 ? { usage } : {} };
3188
+ }
3189
+ async function stepRound(agent, prompt, sendOptions, round, maxRounds, state4) {
3190
+ const run = await agent.send(prompt, sendOptions);
3191
+ const result = await run.wait();
3192
+ const usage = addUsage(state4.usage, result.usage);
3193
+ const decision = classifyRound(result, round, maxRounds, state4.emptyStreak);
3194
+ if (decision !== "continue") return { terminal: buildResult(decision, round, result, usage) };
3195
+ const emptyStreak = isEmptyRound(result) ? state4.emptyStreak + 1 : 0;
3196
+ return { next: { usage, emptyStreak }, lastResult: result };
3197
+ }
3198
+ async function runToCompletionImpl(agent, message, options) {
3199
+ const maxRounds = options?.maxRounds ?? DEFAULT_MAX_ROUNDS;
3200
+ const continuationPrompt = options?.continuationPrompt ?? DEFAULT_CONTINUATION_PROMPT;
3201
+ const { onTruncated, signal, sendOptions } = options ?? {};
3202
+ let state4 = { usage: void 0, emptyStreak: 0 };
3203
+ for (let round = 0; ; round += 1) {
3204
+ const prompt = round === 0 ? message : continuationPrompt;
3205
+ const outcome = await stepRound(agent, prompt, sendOptions, round, maxRounds, state4);
3206
+ if ("terminal" in outcome) return outcome.terminal;
3207
+ state4 = outcome.next;
3208
+ await onTruncated?.({ round });
3209
+ if (signal?.aborted === true) {
3210
+ return buildResult("step_limit", round, outcome.lastResult, state4.usage);
3211
+ }
3212
+ }
3213
+ }
3214
+ var DEFAULT_MAX_ROUNDS;
3215
+ var DEFAULT_CONTINUATION_PROMPT;
3216
+ var init_run_to_completion = __esm({
3217
+ "src/internal/runtime/lifecycle/run-to-completion.ts"() {
3218
+ DEFAULT_MAX_ROUNDS = 5;
3219
+ DEFAULT_CONTINUATION_PROMPT = "Continue from where you left off and finish the task. If it is already complete, give the final answer.";
3220
+ }
3221
+ });
3080
3222
  var fork_agent_exports = {};
3081
3223
  __export(fork_agent_exports, {
3082
3224
  filterMemoryPlugins: () => filterMemoryPlugins,
@@ -3157,55 +3299,14 @@ var init_task = __esm({
3157
3299
  RESERVED_PREFIXES = ["wf-", "b-", "cron-"];
3158
3300
  }
3159
3301
  });
3160
- function createSemaphore(permits) {
3161
- if (!Number.isInteger(permits) || permits < 1) {
3162
- throw new ConfigurationError(
3163
- `async-semaphore: permits must be a positive integer, got ${permits}`,
3164
- { code: "invalid_concurrency" }
3165
- );
3166
- }
3167
- let active = 0;
3168
- const queue = [];
3169
- function tryGrant() {
3170
- if (active < permits && queue.length > 0) {
3171
- const resolve3 = queue.shift();
3172
- if (resolve3 !== void 0) {
3173
- active += 1;
3174
- resolve3();
3175
- }
3176
- }
3177
- }
3178
- return {
3179
- inFlight: () => active,
3180
- pending: () => queue.length + active,
3181
- async acquire() {
3182
- await new Promise((resolve3) => {
3183
- queue.push(resolve3);
3184
- tryGrant();
3185
- });
3186
- let released = false;
3187
- return () => {
3188
- if (released) return;
3189
- released = true;
3190
- active -= 1;
3191
- tryGrant();
3192
- };
3193
- }
3194
- };
3195
- }
3196
- var init_async_semaphore = __esm({
3197
- "src/internal/runtime/concurrency/async-semaphore.ts"() {
3198
- init_errors();
3199
- }
3200
- });
3201
3302
  var RingBuffer;
3202
3303
  var init_ring_buffer = __esm({
3203
3304
  "src/internal/task/ring-buffer.ts"() {
3204
3305
  RingBuffer = class {
3205
- constructor(cap) {
3206
- this.cap = cap;
3207
- if (!Number.isInteger(cap) || cap < 1) {
3208
- throw new Error(`RingBuffer capacity must be a positive integer, got ${cap}`);
3306
+ constructor(cap2) {
3307
+ this.cap = cap2;
3308
+ if (!Number.isInteger(cap2) || cap2 < 1) {
3309
+ throw new Error(`RingBuffer capacity must be a positive integer, got ${cap2}`);
3209
3310
  }
3210
3311
  }
3211
3312
  cap;
@@ -7060,8 +7161,7 @@ var FixtureRunBase = class {
7060
7161
  if (status === "error" && this.script.errorDetail !== void 0) {
7061
7162
  base.error = this.script.errorDetail;
7062
7163
  }
7063
- if (this.script.usage !== void 0) base.usage = this.script.usage;
7064
- if (this.script.cost !== void 0) base.cost = this.script.cost;
7164
+ applyScriptMetrics(base, this.script);
7065
7165
  return this.extendRunResult(applyExtraRunFields(base, this.script));
7066
7166
  }
7067
7167
  /** Subclasses override to attach runtime-specific fields (e.g. cloud git info). */
@@ -7095,6 +7195,11 @@ function makeNotifier() {
7095
7195
  });
7096
7196
  return { promise, resolve: resolve3 };
7097
7197
  }
7198
+ function applyScriptMetrics(base, script) {
7199
+ if (script.usage !== void 0) base.usage = script.usage;
7200
+ if (script.cost !== void 0) base.cost = script.cost;
7201
+ if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
7202
+ }
7098
7203
  function createCloudRun(options) {
7099
7204
  const { userText, id, startTime } = prepareRunContext(options.message);
7100
7205
  const supported = /* @__PURE__ */ new Set([
@@ -7593,6 +7698,18 @@ var CloudAgent = class {
7593
7698
  "fork"
7594
7699
  );
7595
7700
  }
7701
+ /**
7702
+ * The continuation driver re-sends against a stateful local session; the
7703
+ * cloud runtime manages its own continuation policy server-side (M1 Phase 3).
7704
+ *
7705
+ * @public
7706
+ */
7707
+ runToCompletion() {
7708
+ throw new UnsupportedRunOperationError(
7709
+ "Agent.runToCompletion() is not supported on cloud agents. Cloud runtime manages continuation server-side. Use a local agent.",
7710
+ "runToCompletion"
7711
+ );
7712
+ }
7596
7713
  /**
7597
7714
  * Personality presets require consistent server-side enforcement that
7598
7715
  * the cloud runtime (pre-release) does not yet provide. Reject explicitly
@@ -9064,6 +9181,8 @@ function parseSubagentMarkdown(raw, filename) {
9064
9181
  if (fields.model !== void 0) {
9065
9182
  definition.model = fields.model === "inherit" ? "inherit" : { id: fields.model };
9066
9183
  }
9184
+ const tools = fields.tools?.split(/[\s,]+/).map((t) => t.trim()).filter((t) => t.length > 0);
9185
+ if (tools !== void 0 && tools.length > 0) definition.tools = tools;
9067
9186
  return { name, definition };
9068
9187
  }
9069
9188
  function splitFrontmatter2(raw, filename) {
@@ -9210,20 +9329,21 @@ ${lines.join("\n")}
9210
9329
  </memory>`);
9211
9330
  }
9212
9331
  };
9332
+ function buildSkillsBlock(skills) {
9333
+ if (skills.length === 0) return void 0;
9334
+ const lines = skills.map(
9335
+ (skill) => ` - ${escapeBlockBody(skill.name)}: ${escapeBlockBody(skill.description)}`
9336
+ );
9337
+ return `<skills>
9338
+ ${lines.join("\n")}
9339
+ </skills>`;
9340
+ }
9213
9341
  var SkillsPromptProvider = class {
9214
9342
  id = "skills";
9215
9343
  priority = 20;
9216
9344
  contribute(ctx) {
9217
9345
  if (ctx.skillsAutoInject === false) return Promise.resolve(void 0);
9218
- if (ctx.skills.length === 0) return Promise.resolve(void 0);
9219
- const lines = ctx.skills.map((skill) => {
9220
- const name = escapeBlockBody(skill.name);
9221
- const description = escapeBlockBody(skill.description);
9222
- return ` - ${name}: ${description}`;
9223
- });
9224
- return Promise.resolve(`<skills>
9225
- ${lines.join("\n")}
9226
- </skills>`);
9346
+ return Promise.resolve(buildSkillsBlock(ctx.skills));
9227
9347
  }
9228
9348
  };
9229
9349
  var SystemPromptPipeline = class _SystemPromptPipeline {
@@ -10272,7 +10392,7 @@ async function loadPluginManifestFromJson(manifestPath, folderName) {
10272
10392
  const record = parsed;
10273
10393
  const name = typeof record.name === "string" ? record.name : folderName;
10274
10394
  const version = typeof record.version === "string" ? record.version : "0.0.0";
10275
- const capabilities = Array.isArray(record.capabilities) ? record.capabilities.filter((cap) => typeof cap === "string") : [];
10395
+ const capabilities = Array.isArray(record.capabilities) ? record.capabilities.filter((cap2) => typeof cap2 === "string") : [];
10276
10396
  const source = manifestPath.slice(manifestPath.indexOf(".theokit/"));
10277
10397
  const metadata = { name, version, capabilities, source };
10278
10398
  if (typeof record.entry === "string") metadata.entry = record.entry;
@@ -10383,6 +10503,59 @@ function parseDependencies(raw) {
10383
10503
  function hasContent(value) {
10384
10504
  return value !== void 0 && value.trim().length > 0;
10385
10505
  }
10506
+ async function discoverSkills(dir, options) {
10507
+ let entries;
10508
+ try {
10509
+ entries = await readWorkspaceDir(dir, "skills_read_error", "skills directory");
10510
+ } catch {
10511
+ return [];
10512
+ }
10513
+ const skills = [];
10514
+ for (const entry of entries) {
10515
+ if (!entry.isDirectory()) continue;
10516
+ let skillDir;
10517
+ try {
10518
+ skillDir = safePathJoin(dir, entry.name);
10519
+ assertNoSymlinkEscape(skillDir, dir);
10520
+ } catch {
10521
+ continue;
10522
+ }
10523
+ const skillPath = join(skillDir, "SKILL.md");
10524
+ let raw;
10525
+ try {
10526
+ raw = await readFile(skillPath, "utf8");
10527
+ } catch {
10528
+ continue;
10529
+ }
10530
+ const skill = tryParseSkill(raw, entry.name, skillPath, options);
10531
+ if (skill !== void 0) skills.push(skill);
10532
+ }
10533
+ return skills;
10534
+ }
10535
+ function tryParseSkill(raw, fallbackName, source, options) {
10536
+ try {
10537
+ const frontmatter = parseSkillFrontmatter(raw, fallbackName);
10538
+ const skill = {
10539
+ name: frontmatter.name,
10540
+ description: frontmatter.description,
10541
+ source
10542
+ };
10543
+ if (frontmatter.category !== void 0) skill.category = frontmatter.category;
10544
+ if (frontmatter.dependencies !== void 0) skill.dependencies = frontmatter.dependencies;
10545
+ return skill;
10546
+ } catch (cause) {
10547
+ if (cause instanceof ConfigurationError) {
10548
+ options?.onInvalidSkill?.({
10549
+ name: fallbackName,
10550
+ source,
10551
+ code: cause.code ?? "unknown",
10552
+ message: cause.message
10553
+ });
10554
+ return void 0;
10555
+ }
10556
+ throw cause;
10557
+ }
10558
+ }
10386
10559
  var SkillsManager = class {
10387
10560
  constructor(cwd, _enabled, settingSourcesIncludeProject) {
10388
10561
  this.cwd = cwd;
@@ -10399,56 +10572,20 @@ var SkillsManager = class {
10399
10572
  await this.refresh();
10400
10573
  }
10401
10574
  async refresh() {
10402
- this.skills = [];
10403
10575
  const skillsRoot = join(this.cwd, ".theokit", "skills");
10404
- const entries = await readWorkspaceDir(skillsRoot, "skills_read_error", "skills directory");
10405
- for (const entry of entries) {
10406
- if (!entry.isDirectory()) continue;
10407
- let skillDir;
10408
- try {
10409
- skillDir = safePathJoin(skillsRoot, entry.name);
10410
- assertNoSymlinkEscape(skillDir, skillsRoot);
10411
- } catch {
10412
- continue;
10413
- }
10414
- const skillPath = join(skillDir, "SKILL.md");
10415
- let raw;
10416
- try {
10417
- raw = await readFile(skillPath, "utf8");
10418
- } catch {
10419
- continue;
10576
+ this.skills = await discoverSkills(skillsRoot, {
10577
+ onInvalidSkill: (info) => {
10578
+ process.stderr.write(
10579
+ `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
10580
+ `
10581
+ );
10420
10582
  }
10421
- const metadata = tryParseSkill(raw, entry.name, skillPath);
10422
- if (metadata !== void 0) this.skills.push(metadata);
10423
- }
10583
+ });
10424
10584
  }
10425
10585
  list() {
10426
10586
  return Promise.resolve(this.skills);
10427
10587
  }
10428
10588
  };
10429
- function tryParseSkill(raw, fallbackName, source) {
10430
- try {
10431
- const frontmatter = parseSkillFrontmatter(raw, fallbackName);
10432
- const metadata = {
10433
- name: frontmatter.name,
10434
- description: frontmatter.description,
10435
- source
10436
- };
10437
- if (frontmatter.category !== void 0) metadata.category = frontmatter.category;
10438
- if (frontmatter.dependencies !== void 0) metadata.dependencies = frontmatter.dependencies;
10439
- return metadata;
10440
- } catch (cause) {
10441
- if (cause instanceof ConfigurationError) {
10442
- const code = cause.code ?? "unknown";
10443
- process.stderr.write(
10444
- `[theokit-sdk] skill ${fallbackName} skipped (${code}): ${cause.message}
10445
- `
10446
- );
10447
- return void 0;
10448
- }
10449
- throw cause;
10450
- }
10451
- }
10452
10589
  function registerLocalAgent(args) {
10453
10590
  registerAgent({
10454
10591
  agentId: args.agentId,
@@ -10582,6 +10719,7 @@ var LocalRun = class extends FixtureRunBase {
10582
10719
  }
10583
10720
  }
10584
10721
  };
10722
+ init_errors();
10585
10723
  var IterationBudget = class {
10586
10724
  #remaining;
10587
10725
  #total;
@@ -10840,6 +10978,7 @@ async function initLoopContext(inputs) {
10840
10978
  finalStatus: "finished",
10841
10979
  usage: new UsageAccumulator(),
10842
10980
  nudgeAttempts: 0,
10981
+ stopFeedbackAttempts: 0,
10843
10982
  ...memoryProviderHandle !== void 0 ? { memoryProviderHandle } : {},
10844
10983
  ...memorySystemPromptAdditions !== void 0 ? { memorySystemPromptAdditions } : {}
10845
10984
  };
@@ -10980,8 +11119,9 @@ function registerLoopError(ctx, cause) {
10980
11119
  if (ctx.error !== void 0) return;
10981
11120
  const rawMessage = cause?.message;
10982
11121
  const message = typeof rawMessage === "string" ? rawMessage : cause instanceof Error ? cause.message : String(cause);
11122
+ const metaCode = cause?.metadata?.code;
10983
11123
  const rawCode = cause?.code;
10984
- const code = typeof rawCode === "string" ? rawCode : void 0;
11124
+ const code = typeof metaCode === "string" ? metaCode : typeof rawCode === "string" ? rawCode : void 0;
10985
11125
  ctx.error = code !== void 0 ? { message, code, cause } : { message, cause };
10986
11126
  }
10987
11127
  async function runCollectorLoop(generator, inputs, ctx) {
@@ -11017,6 +11157,25 @@ async function emitTextDeltaCallback(inputs, text) {
11017
11157
  );
11018
11158
  }
11019
11159
  init_async_local_storage();
11160
+ init_async_semaphore();
11161
+ var NEVER_ABORT = new AbortController().signal;
11162
+ async function mapWithConcurrency(items, concurrency, fn, options) {
11163
+ const semaphore = createSemaphore(concurrency);
11164
+ const signal = NEVER_ABORT;
11165
+ return Promise.all(
11166
+ items.map(async (item, index) => {
11167
+ const release = await semaphore.acquire();
11168
+ try {
11169
+ if (signal.aborted) {
11170
+ throw signal.reason instanceof Error ? signal.reason : new Error("mapWithConcurrency: aborted");
11171
+ }
11172
+ return await fn(item, index, signal);
11173
+ } finally {
11174
+ release();
11175
+ }
11176
+ })
11177
+ );
11178
+ }
11020
11179
  var DECIMAL_RE = /^-?\d+(\.\d+)?$/;
11021
11180
  function repairToolCall(raw, registry3) {
11022
11181
  const repairs = [];
@@ -11184,38 +11343,12 @@ ${result.stderr}`.trim();
11184
11343
  }
11185
11344
  async function dispatchTools(inputs, tools, toolCalls, events) {
11186
11345
  const maxConcurrent = inputs.maxConcurrentTools ?? 4;
11187
- return boundedParallel(
11188
- maxConcurrent,
11346
+ return mapWithConcurrency(
11189
11347
  toolCalls,
11348
+ maxConcurrent,
11190
11349
  (call) => dispatchSingleCall(inputs, tools, call, events)
11191
11350
  );
11192
11351
  }
11193
- async function boundedParallel(max, items, fn) {
11194
- let running = 0;
11195
- const queue = [];
11196
- async function acquire() {
11197
- if (running < max) {
11198
- running++;
11199
- return;
11200
- }
11201
- await new Promise((resolve3) => queue.push(resolve3));
11202
- running++;
11203
- }
11204
- function release() {
11205
- running--;
11206
- if (queue.length > 0) queue.shift()();
11207
- }
11208
- return Promise.all(
11209
- items.map(async (item) => {
11210
- await acquire();
11211
- try {
11212
- return await fn(item);
11213
- } finally {
11214
- release();
11215
- }
11216
- })
11217
- );
11218
- }
11219
11352
  async function dispatchSingleCall(inputs, tools, call, events) {
11220
11353
  const { call: workingCall, repairs } = applyRepairAndExtractCall(tools, call);
11221
11354
  const callId = generateCallId();
@@ -11761,6 +11894,7 @@ function computeUsageCost(inputs, usage) {
11761
11894
  return computeCost({ provider, model, usage });
11762
11895
  }
11763
11896
  var MAX_NUDGE_ATTEMPTS = 2;
11897
+ var MAX_STOP_FEEDBACK_ATTEMPTS = 2;
11764
11898
  async function runAgentLoop(inputs) {
11765
11899
  const sendSpan = inputs.telemetry?.startSpan("agent.send", {
11766
11900
  agentId: inputs.agentId,
@@ -11775,6 +11909,7 @@ async function runAgentLoop(inputs) {
11775
11909
  const ctx = await initLoopContext(inputs);
11776
11910
  ctxRef = ctx;
11777
11911
  const budget = inputs.budget ?? new IterationBudget({ maxIterations: inputs.maxIterations ?? 8 });
11912
+ let lastTurnDecision;
11778
11913
  while (budget.shouldContinue()) {
11779
11914
  if (inputs.budgetTracker !== void 0) {
11780
11915
  const decision2 = evaluateBudgetGate(inputs.budgetTracker);
@@ -11783,18 +11918,26 @@ async function runAgentLoop(inputs) {
11783
11918
  if (decision2.detail !== void 0) {
11784
11919
  ctx.error = { message: decision2.detail, code: decision2.reason ?? "budget" };
11785
11920
  }
11921
+ if (decision2.reason === "iteration_limit") {
11922
+ ctx.stoppedAtIterationLimit = true;
11923
+ }
11786
11924
  break;
11787
11925
  }
11788
11926
  }
11789
11927
  const usingGrace = budget.remaining <= 0 && !budget.graceCallUsed;
11790
11928
  if (usingGrace) budget.useGraceCall();
11791
11929
  const decision = await runIteration(inputs, ctx);
11930
+ lastTurnDecision = decision;
11792
11931
  if (decision === "done") break;
11793
11932
  if (decision === "error") {
11794
11933
  ctx.finalStatus = "error";
11795
11934
  break;
11796
11935
  }
11797
11936
  budget.consume();
11937
+ inputs.budgetTracker?.nextIteration?.();
11938
+ }
11939
+ if (lastTurnDecision === "continue" && budget.shouldContinue() === false) {
11940
+ ctx.stoppedAtIterationLimit = true;
11798
11941
  }
11799
11942
  if (budget.shouldContinue() === false && ctx.finalStatus === "finished" && ctx.finalText === "") {
11800
11943
  ctx.finalStatus = "error";
@@ -11825,7 +11968,8 @@ async function runAgentLoop(inputs) {
11825
11968
  conversation: ctx.conversation,
11826
11969
  ...usage !== void 0 ? { usage } : {},
11827
11970
  ...cost !== void 0 ? { cost } : {},
11828
- ...ctx.error !== void 0 ? { error: ctx.error } : {}
11971
+ ...ctx.error !== void 0 ? { error: ctx.error } : {},
11972
+ ...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {}
11829
11973
  };
11830
11974
  } finally {
11831
11975
  if (ctxRef !== void 0 && ctxRef.memoryProviderHandle !== void 0 && inputs.memoryProvider !== void 0) {
@@ -11882,8 +12026,8 @@ function handleToolErrorContinuation(inputs, ctx, toolResults) {
11882
12026
  const hasError = toolResults.some((part) => part.type === "tool_result" && part.isError === true);
11883
12027
  if (hasError) {
11884
12028
  ctx._consecutiveToolErrors = (ctx._consecutiveToolErrors ?? 0) + 1;
11885
- const cap = inputs.maxConsecutiveToolErrors ?? 3;
11886
- if (ctx._consecutiveToolErrors >= cap) return "error";
12029
+ const cap2 = inputs.maxConsecutiveToolErrors ?? 3;
12030
+ if (ctx._consecutiveToolErrors >= cap2) return "error";
11887
12031
  return "continue";
11888
12032
  }
11889
12033
  ctx._consecutiveToolErrors = 0;
@@ -11908,6 +12052,28 @@ function shouldNudgeAndContinue(ctx, llmOutput) {
11908
12052
  });
11909
12053
  return true;
11910
12054
  }
12055
+ async function reflectAfterStop(inputs, ctx) {
12056
+ const result = await inputs.hooks.run({
12057
+ event: "stop",
12058
+ agentId: inputs.agentId,
12059
+ runId: inputs.runId
12060
+ });
12061
+ if (result.blocked) return false;
12062
+ if (ctx.stopFeedbackAttempts >= MAX_STOP_FEEDBACK_ATTEMPTS) return false;
12063
+ const feedback = result.decisions.find(
12064
+ (d2) => d2.decision === "feedback" && (d2.feedback ?? "").length > 0
12065
+ )?.feedback;
12066
+ if (feedback === void 0) return false;
12067
+ ctx.stopFeedbackAttempts += 1;
12068
+ ctx.messages.push({ role: "user", content: [{ type: "text", text: feedback }] });
12069
+ return true;
12070
+ }
12071
+ async function finishOrReflect(inputs, ctx, llmOutput) {
12072
+ if (shouldNudgeAndContinue(ctx, llmOutput)) return "continue";
12073
+ if (await reflectAfterStop(inputs, ctx)) return "continue";
12074
+ ctx.finalStatus = "finished";
12075
+ return "done";
12076
+ }
11911
12077
  async function runIteration(inputs, ctx) {
11912
12078
  const llmOutput = await streamLlmTurn(inputs, ctx);
11913
12079
  accumulateUsage(ctx.usage, llmOutput);
@@ -11941,9 +12107,7 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
11941
12107
  await emitAssistantTextStep(inputs, ctx, llmOutput.text);
11942
12108
  }
11943
12109
  if (llmOutput.stopReason !== "tool_use" || llmOutput.toolCalls.length === 0) {
11944
- if (shouldNudgeAndContinue(ctx, llmOutput)) return "continue";
11945
- ctx.finalStatus = "finished";
11946
- return "done";
12110
+ return finishOrReflect(inputs, ctx, llmOutput);
11947
12111
  }
11948
12112
  ctx.messages.push(buildAssistantTurn(llmOutput.text, llmOutput.toolCalls));
11949
12113
  const toolResults = await dispatchTools(inputs, ctx.tools, llmOutput.toolCalls, ctx.events);
@@ -14073,6 +14237,14 @@ function resolveMcpCwd(configCwd) {
14073
14237
  if (isAbsolute(configCwd)) return configCwd;
14074
14238
  return safePathJoin(process.cwd(), configCwd);
14075
14239
  }
14240
+ function registerPluginProviderProfiles(entries) {
14241
+ let registered4 = 0;
14242
+ for (const entry of entries) {
14243
+ registerProvider(entry.profile);
14244
+ registered4 += 1;
14245
+ }
14246
+ return registered4;
14247
+ }
14076
14248
  init_hooks_source();
14077
14249
  function applyPersonalityFilter(exposedTools, whitelist, opts) {
14078
14250
  if (whitelist === void 0) return exposedTools;
@@ -14146,12 +14318,34 @@ function createRealLocalRun(options) {
14146
14318
  registerRun(handle);
14147
14319
  return handle;
14148
14320
  }
14149
- function buildLoopInputs(options, runId, userText) {
14321
+ var pluginProvidersAnnounced = false;
14322
+ function resolveRunProvider(options) {
14150
14323
  registerBuiltins();
14324
+ const profiles = options.pluginManager?.aggregated.providerProfiles ?? [];
14325
+ const registered4 = registerPluginProviderProfiles(profiles);
14326
+ if (registered4 > 0 && !pluginProvidersAnnounced) {
14327
+ pluginProvidersAnnounced = true;
14328
+ const names = profiles.map((e) => e.profile.name).join(", ");
14329
+ process.stderr.write(
14330
+ `[theokit-sdk] registered ${registered4} plugin provider profile(s): ${names}
14331
+ `
14332
+ );
14333
+ }
14151
14334
  const parsedModel = parseModelId(options.model?.id);
14152
14335
  const inferredProvider = parsedModel.provider !== void 0 && getProviderProfile(parsedModel.provider) !== void 0 ? parsedModel.provider : void 0;
14153
14336
  const primary = options.agentOptions.providers?.routes?.[0]?.provider ?? inferredProvider ?? detectPrimaryProvider();
14154
14337
  const effectiveModelId = inferredProvider !== void 0 ? parsedModel.name : options.model?.id ?? "claude-sonnet-4-6";
14338
+ return { primary, effectiveModelId };
14339
+ }
14340
+ function buildLoopInputs(options, runId, userText) {
14341
+ const maxIterations = options.sendOptions.maxIterations;
14342
+ if (maxIterations !== void 0 && (!Number.isInteger(maxIterations) || maxIterations < 1)) {
14343
+ throw new ConfigurationError(
14344
+ `SendOptions.maxIterations must be a positive integer, got ${maxIterations}`,
14345
+ { code: "invalid_max_iterations" }
14346
+ );
14347
+ }
14348
+ const { primary, effectiveModelId } = resolveRunProvider(options);
14155
14349
  const fallback = options.agentOptions.providers?.fallback;
14156
14350
  const apiKeys = options.agentOptions.providers?.apiKeys;
14157
14351
  const credentialPoolStrategy = options.agentOptions.providers?.credentialPoolStrategy;
@@ -14189,6 +14383,9 @@ function buildLoopInputs(options, runId, userText) {
14189
14383
  // D318 — forward SendOptions.signal to the agent loop so streamLlmTurn
14190
14384
  // can attach it to the LLM `fetch({ signal })` call.
14191
14385
  ...options.sendOptions.signal !== void 0 ? { signal: options.sendOptions.signal } : {},
14386
+ // M1-2: per-send iteration ceiling (validated above). The loop reads
14387
+ // inputs.maxIterations (default 8 when unset).
14388
+ ...maxIterations !== void 0 ? { maxIterations } : {},
14192
14389
  // D315-D317 — tool lifecycle hooks (cost tracking + audit + retry/alert)
14193
14390
  ...options.agentOptions.onToolStart !== void 0 ? { onToolStart: options.agentOptions.onToolStart } : {},
14194
14391
  ...options.agentOptions.onToolEnd !== void 0 ? { onToolEnd: options.agentOptions.onToolEnd } : {},
@@ -14320,6 +14517,7 @@ var RealLocalRun = class extends FixtureRunBase {
14320
14517
  if (output.result.length > 0) this.script.result = output.result;
14321
14518
  if (output.usage !== void 0) this.script.usage = output.usage;
14322
14519
  if (output.cost !== void 0) this.script.cost = output.cost;
14520
+ if (output.stoppedAtIterationLimit === true) this.script.stoppedAtIterationLimit = true;
14323
14521
  if (output.error !== void 0 && this.script.errorDetail === void 0) {
14324
14522
  this.script.errorDetail = {
14325
14523
  message: output.error.message,
@@ -14731,7 +14929,7 @@ async function embedTexts(input) {
14731
14929
  pending
14732
14930
  });
14733
14931
  }
14734
- await runBatches(input, pending, results);
14932
+ await embedInBoundedBatches(input, pending, results);
14735
14933
  return results.map((v2) => v2 ?? new Array(dimension).fill(0));
14736
14934
  }
14737
14935
  function classifyEntry(args) {
@@ -14750,45 +14948,34 @@ function classifyEntry(args) {
14750
14948
  args.pending.push({ index: args.index, text: args.text, key: key2 });
14751
14949
  }
14752
14950
  var MAX_CONCURRENT_BATCHES = 3;
14753
- async function runBatches(input, pending, results) {
14951
+ async function embedInBoundedBatches(input, pending, results) {
14754
14952
  const batches = [];
14755
14953
  for (let offset = 0; offset < pending.length; offset += MAX_BATCH) {
14756
14954
  batches.push(pending.slice(offset, offset + MAX_BATCH));
14757
14955
  }
14758
- let running = 0;
14759
- const queue = [];
14760
- await Promise.all(batches.map((batch) => processBatch(input, batch, results, acquire, release)));
14761
- async function acquire() {
14762
- if (running >= MAX_CONCURRENT_BATCHES) await new Promise((r) => queue.push(r));
14763
- running++;
14764
- }
14765
- function release() {
14766
- running--;
14767
- if (queue.length > 0) queue.shift()();
14768
- }
14956
+ await mapWithConcurrency(
14957
+ batches,
14958
+ MAX_CONCURRENT_BATCHES,
14959
+ (batch) => processBatch(input, batch, results)
14960
+ );
14769
14961
  }
14770
- async function processBatch(input, batch, results, acquire, release) {
14771
- await acquire();
14772
- try {
14773
- const vectors = await embedBatch({
14774
- apiKey: input.apiKey,
14775
- baseUrl: input.baseUrl,
14776
- embeddingsPath: input.embeddingsPath,
14777
- model: input.model,
14778
- inputs: batch.map((b2) => b2.text),
14779
- fetchImpl: input.fetchImpl,
14780
- stats: input.stats,
14781
- providerId: input.providerId
14782
- });
14783
- for (let j = 0; j < batch.length; j++) {
14784
- const slot = batch[j];
14785
- const vector = vectors[j];
14786
- if (slot === void 0 || vector === void 0) continue;
14787
- results[slot.index] = vector;
14788
- input.cache.set(slot.key, vector);
14789
- }
14790
- } finally {
14791
- release();
14962
+ async function processBatch(input, batch, results) {
14963
+ const vectors = await embedBatch({
14964
+ apiKey: input.apiKey,
14965
+ baseUrl: input.baseUrl,
14966
+ embeddingsPath: input.embeddingsPath,
14967
+ model: input.model,
14968
+ inputs: batch.map((b2) => b2.text),
14969
+ fetchImpl: input.fetchImpl,
14970
+ stats: input.stats,
14971
+ providerId: input.providerId
14972
+ });
14973
+ for (let j = 0; j < batch.length; j++) {
14974
+ const slot = batch[j];
14975
+ const vector = vectors[j];
14976
+ if (slot === void 0 || vector === void 0) continue;
14977
+ results[slot.index] = vector;
14978
+ input.cache.set(slot.key, vector);
14792
14979
  }
14793
14980
  }
14794
14981
  async function embedBatch(opts) {
@@ -15228,7 +15415,7 @@ var MEMORY_GET_SCHEMA = {
15228
15415
  };
15229
15416
  var DEFAULT_MAX_TOTAL_CHARS = 16384;
15230
15417
  function createMemorySearchTool(opts) {
15231
- const cap = opts.maxTotalChars ?? DEFAULT_MAX_TOTAL_CHARS;
15418
+ const cap2 = opts.maxTotalChars ?? DEFAULT_MAX_TOTAL_CHARS;
15232
15419
  return {
15233
15420
  name: "memory_search",
15234
15421
  description: SEARCH_DESCRIPTION,
@@ -15245,7 +15432,7 @@ function createMemorySearchTool(opts) {
15245
15432
  ...sources !== void 0 ? { sources } : {}
15246
15433
  };
15247
15434
  const hits = await opts.index.search(query, searchOptions);
15248
- return JSON.stringify(capByTotalChars(hits, cap));
15435
+ return JSON.stringify(capByTotalChars(hits, cap2));
15249
15436
  }
15250
15437
  };
15251
15438
  }
@@ -15793,6 +15980,13 @@ function localAgentRunUntil(agent, goal, options) {
15793
15980
  }
15794
15981
  return wrap();
15795
15982
  }
15983
+ function localAgentRunToCompletion(agent, message, options) {
15984
+ async function run() {
15985
+ const { runToCompletionImpl: runToCompletionImpl2 } = await Promise.resolve().then(() => (init_run_to_completion(), run_to_completion_exports));
15986
+ return runToCompletionImpl2({ send: (m2, o) => agent.send(m2, o) }, message, options);
15987
+ }
15988
+ return run();
15989
+ }
15796
15990
  async function localAgentFork(parent, options) {
15797
15991
  const { forkAgentImpl: forkAgentImpl2 } = await Promise.resolve().then(() => (init_fork_agent(), fork_agent_exports));
15798
15992
  const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
@@ -15850,8 +16044,8 @@ async function applyPreUserSendHook(args) {
15850
16044
  ...args.options.memoryContext !== void 0 ? { memoryContext: args.options.memoryContext } : {},
15851
16045
  ...args.sendOptions.signal !== void 0 ? { signal: args.sendOptions.signal } : {}
15852
16046
  };
15853
- const cap = args.options.maxRecallContextBytes ?? DEFAULT_MAX_RECALL_BYTES;
15854
- const recalled = await args.pluginManager.runPreUserSendHooks(ctx, cap);
16047
+ const cap2 = args.options.maxRecallContextBytes ?? DEFAULT_MAX_RECALL_BYTES;
16048
+ const recalled = await args.pluginManager.runPreUserSendHooks(ctx, cap2);
15855
16049
  if (recalled === void 0 || recalled.length === 0) return args.original;
15856
16050
  const wrapped = `<memory-context>
15857
16051
  ${recalled}
@@ -16321,6 +16515,10 @@ var LocalAgent = class {
16321
16515
  fork(options) {
16322
16516
  return localAgentFork({ agentId: this.agentId, options: this.options, personalitySlugSnapshot: this.personalityStore.active(this.agentId) }, options);
16323
16517
  }
16518
+ // biome-ignore format: G8 budget — see runUntil comment above.
16519
+ runToCompletion(message, options) {
16520
+ return localAgentRunToCompletion(this, message, options);
16521
+ }
16324
16522
  };
16325
16523
  function resolveCwd(cwd) {
16326
16524
  return (Array.isArray(cwd) ? cwd[0] : cwd) ?? process.cwd();
@@ -17652,6 +17850,14 @@ async function updateJobStatus(jobId, enabled) {
17652
17850
  }
17653
17851
  return updated;
17654
17852
  }
17853
+ function defineProvider(profile, opts) {
17854
+ return {
17855
+ name: profile.name,
17856
+ version: opts?.version ?? "1.0.0",
17857
+ kind: "model-provider",
17858
+ profile
17859
+ };
17860
+ }
17655
17861
  init_to_json_schema();
17656
17862
  function defineTool(spec) {
17657
17863
  const inputSchema = toJsonSchema(spec.inputSchema, {
@@ -17775,6 +17981,75 @@ function createCounterBudgetTracker(options = {}) {
17775
17981
  }
17776
17982
  };
17777
17983
  }
17984
+ var CHARS_PER_TOKEN = 4;
17985
+ var DEFAULT_RESERVE_TOKENS = 8e3;
17986
+ function finiteOr(value, fallback) {
17987
+ return Number.isFinite(value) ? value : fallback;
17988
+ }
17989
+ function charBudget(options) {
17990
+ const window = finiteOr(options.contextWindowTokens, 0);
17991
+ const reserve = finiteOr(options.reserveTokens ?? DEFAULT_RESERVE_TOKENS, DEFAULT_RESERVE_TOKENS);
17992
+ return Math.max(0, window - reserve) * CHARS_PER_TOKEN;
17993
+ }
17994
+ function assistantText2(event) {
17995
+ return event.message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
17996
+ }
17997
+ function stringifyPayload(value) {
17998
+ if (value === void 0) return "";
17999
+ return typeof value === "string" ? value : JSON.stringify(value) ?? "";
18000
+ }
18001
+ function cap(content, perItemCap) {
18002
+ return truncateWithMarker(content, Math.max(0, perItemCap)).finalContent;
18003
+ }
18004
+ function mapEvent(event, perItemCap) {
18005
+ if (event.type === "assistant") {
18006
+ const text = assistantText2(event);
18007
+ return text.length > 0 ? { message: { role: "assistant", content: cap(text, perItemCap) } } : null;
18008
+ }
18009
+ if (event.type === "tool_call") {
18010
+ if (event.status === "running") {
18011
+ const content2 = cap(`[tool_call ${event.name}] ${stringifyPayload(event.args)}`, perItemCap);
18012
+ return { message: { role: "tool_call", content: content2 }, pairId: event.call_id };
18013
+ }
18014
+ const content = cap(
18015
+ `[tool_result ${event.name}] ${stringifyPayload(event.result)}`,
18016
+ perItemCap
18017
+ );
18018
+ return { message: { role: "tool_result", content }, pairId: event.call_id };
18019
+ }
18020
+ return null;
18021
+ }
18022
+ function evictionIndices(turns) {
18023
+ const head = turns[0];
18024
+ if (head?.pairId === void 0) return [0];
18025
+ const indices = [];
18026
+ for (let i = 0; i < turns.length; i += 1) {
18027
+ if (turns[i]?.pairId === head.pairId) indices.push(i);
18028
+ }
18029
+ return indices;
18030
+ }
18031
+ function totalChars(turns) {
18032
+ return turns.reduce((n2, t) => n2 + t.message.content.length, 0);
18033
+ }
18034
+ function trimToBudget(turns, budgetChars) {
18035
+ const kept = [...turns];
18036
+ while (kept.length > 1 && totalChars(kept) > budgetChars) {
18037
+ const evict = evictionIndices(kept);
18038
+ if (kept.length - evict.length < 1) break;
18039
+ for (const idx of evict.sort((a, b2) => b2 - a)) kept.splice(idx, 1);
18040
+ }
18041
+ return kept;
18042
+ }
18043
+ function buildReplayHistory(base, events, options) {
18044
+ const budgetChars = charBudget(options);
18045
+ const perItemCap = Math.max(0, options.perItemCap ?? Math.floor(budgetChars / 2));
18046
+ const turns = base.map((message) => ({ message }));
18047
+ for (const event of events) {
18048
+ const turn = mapEvent(event, perItemCap);
18049
+ if (turn !== null) turns.push(turn);
18050
+ }
18051
+ return trimToBudget(turns, budgetChars).map((t) => t.message);
18052
+ }
17778
18053
  var NOOP_ADAPTER_ID = "noop";
17779
18054
  var NOOP_CAPABILITIES = {
17780
18055
  history: false,
@@ -18336,24 +18611,44 @@ async function migrateSqliteToLance2(options) {
18336
18611
  return migrateSqliteToLance(options);
18337
18612
  }
18338
18613
  var PermissionEngine = class {
18339
- constructor(rules) {
18614
+ constructor(rules, options = {}) {
18340
18615
  this.rules = rules;
18616
+ this.defaultAction = options.defaultAction ?? "allow";
18341
18617
  }
18342
18618
  rules;
18619
+ defaultAction;
18343
18620
  /**
18344
- * Evaluate a tool name against the rules. First match wins; default "allow".
18621
+ * Evaluate a tool name against the rules. First match wins; falls back to the
18622
+ * configured `defaultAction` (default `"allow"`) when no rule matches.
18345
18623
  */
18346
18624
  evaluate(toolName) {
18347
18625
  for (const rule of this.rules) {
18348
- if (typeof rule.tool === "string") {
18349
- if (rule.tool === toolName) return rule.action;
18350
- } else {
18351
- if (rule.tool.test(toolName)) return rule.action;
18352
- }
18626
+ const matches = typeof rule.tool === "string" ? rule.tool === toolName : rule.tool.test(toolName);
18627
+ if (matches) return rule.action;
18353
18628
  }
18354
- return "allow";
18629
+ return this.defaultAction;
18355
18630
  }
18356
18631
  };
18632
+ function createPermissionPlugin(engine, opts = {}) {
18633
+ return definePlugin({
18634
+ name: opts.name ?? "permission-engine",
18635
+ version: "1.0.0",
18636
+ kind: "general",
18637
+ register(ctx) {
18638
+ ctx.on("pre_tool_call", (rawCtx) => {
18639
+ const { name } = rawCtx;
18640
+ const action = engine.evaluate(name);
18641
+ if (action === "deny") {
18642
+ return { block: true, message: `denied by permission engine: ${name}` };
18643
+ }
18644
+ if (action === "ask") {
18645
+ return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
18646
+ }
18647
+ return void 0;
18648
+ });
18649
+ }
18650
+ });
18651
+ }
18357
18652
  init_security();
18358
18653
  var Security = class {
18359
18654
  constructor() {
@@ -19134,17 +19429,21 @@ export {
19134
19429
  UnsupportedRunOperationError,
19135
19430
  UnsupportedTaskOperationError,
19136
19431
  UsageAccumulator,
19432
+ buildReplayHistory,
19137
19433
  chargeAndCheckThresholds,
19138
19434
  computeCost,
19139
19435
  createAgentFactory,
19140
19436
  createCounterBudgetTracker,
19141
19437
  createNoopMemoryProvider,
19438
+ createPermissionPlugin,
19142
19439
  createSquad,
19143
19440
  definePlugin,
19441
+ defineProvider,
19144
19442
  defineTool,
19145
19443
  extractRawId,
19146
19444
  getPricingEntry,
19147
19445
  inferApiMode,
19446
+ isTransientError,
19148
19447
  migrateSqliteToLance2 as migrateSqliteToLance,
19149
19448
  mkMemoryId,
19150
19449
  normalizeUsage,
@@ -19152,4 +19451,4 @@ export {
19152
19451
  toShareGptTrajectory,
19153
19452
  withCwdMutex
19154
19453
  };
19155
- //# sourceMappingURL=dist-6GPD6WCU.js.map
19454
+ //# sourceMappingURL=dist-IW7G5Y23.js.map