@theokit/sdk 2.1.0 → 2.3.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/dist/eval.js CHANGED
@@ -1436,6 +1436,71 @@ var init_agent_factory_registry = __esm({
1436
1436
  }
1437
1437
  });
1438
1438
 
1439
+ // src/internal/runtime/lifecycle/run-to-completion.ts
1440
+ var run_to_completion_exports = {};
1441
+ __export(run_to_completion_exports, {
1442
+ classifyRound: () => classifyRound,
1443
+ runToCompletionImpl: () => runToCompletionImpl
1444
+ });
1445
+ function isEmptyRound(result) {
1446
+ return (result.result ?? "").trim() === "";
1447
+ }
1448
+ function classifyRound(result, round, maxRounds, emptyStreak) {
1449
+ if (result.stoppedAtIterationLimit !== true) return "done";
1450
+ if (isEmptyRound(result) && emptyStreak >= 1) return "no_progress";
1451
+ if (round >= maxRounds) return "step_limit";
1452
+ return "continue";
1453
+ }
1454
+ function addUsage(acc, u) {
1455
+ if (u === void 0) return acc;
1456
+ const inputTokens = (acc?.inputTokens ?? 0) + u.inputTokens;
1457
+ const outputTokens = (acc?.outputTokens ?? 0) + u.outputTokens;
1458
+ const sumOpt = (a, b) => a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
1459
+ return {
1460
+ inputTokens,
1461
+ outputTokens,
1462
+ totalTokens: inputTokens + outputTokens,
1463
+ cacheReadTokens: sumOpt(acc?.cacheReadTokens, u.cacheReadTokens),
1464
+ cacheWriteTokens: sumOpt(acc?.cacheWriteTokens, u.cacheWriteTokens),
1465
+ reasoningTokens: sumOpt(acc?.reasoningTokens, u.reasoningTokens)
1466
+ };
1467
+ }
1468
+ function buildResult(terminal, rounds, lastResult, usage) {
1469
+ return { terminal, rounds, lastResult, ...usage !== void 0 ? { usage } : {} };
1470
+ }
1471
+ async function stepRound(agent, prompt, sendOptions, round, maxRounds, state2) {
1472
+ const run = await agent.send(prompt, sendOptions);
1473
+ const result = await run.wait();
1474
+ const usage = addUsage(state2.usage, result.usage);
1475
+ const decision = classifyRound(result, round, maxRounds, state2.emptyStreak);
1476
+ if (decision !== "continue") return { terminal: buildResult(decision, round, result, usage) };
1477
+ const emptyStreak = isEmptyRound(result) ? state2.emptyStreak + 1 : 0;
1478
+ return { next: { usage, emptyStreak }, lastResult: result };
1479
+ }
1480
+ async function runToCompletionImpl(agent, message, options) {
1481
+ const maxRounds = options?.maxRounds ?? DEFAULT_MAX_ROUNDS;
1482
+ const continuationPrompt = options?.continuationPrompt ?? DEFAULT_CONTINUATION_PROMPT;
1483
+ const { onTruncated, signal, sendOptions } = options ?? {};
1484
+ let state2 = { usage: void 0, emptyStreak: 0 };
1485
+ for (let round = 0; ; round += 1) {
1486
+ const prompt = round === 0 ? message : continuationPrompt;
1487
+ const outcome = await stepRound(agent, prompt, sendOptions, round, maxRounds, state2);
1488
+ if ("terminal" in outcome) return outcome.terminal;
1489
+ state2 = outcome.next;
1490
+ await onTruncated?.({ round });
1491
+ if (signal?.aborted === true) {
1492
+ return buildResult("step_limit", round, outcome.lastResult, state2.usage);
1493
+ }
1494
+ }
1495
+ }
1496
+ var DEFAULT_MAX_ROUNDS, DEFAULT_CONTINUATION_PROMPT;
1497
+ var init_run_to_completion = __esm({
1498
+ "src/internal/runtime/lifecycle/run-to-completion.ts"() {
1499
+ DEFAULT_MAX_ROUNDS = 5;
1500
+ DEFAULT_CONTINUATION_PROMPT = "Continue from where you left off and finish the task. If it is already complete, give the final answer.";
1501
+ }
1502
+ });
1503
+
1439
1504
  // src/internal/runtime/lifecycle/fork-agent.ts
1440
1505
  var fork_agent_exports = {};
1441
1506
  __export(fork_agent_exports, {
@@ -4312,8 +4377,7 @@ var FixtureRunBase = class {
4312
4377
  if (status === "error" && this.script.errorDetail !== void 0) {
4313
4378
  base.error = this.script.errorDetail;
4314
4379
  }
4315
- if (this.script.usage !== void 0) base.usage = this.script.usage;
4316
- if (this.script.cost !== void 0) base.cost = this.script.cost;
4380
+ applyScriptMetrics(base, this.script);
4317
4381
  return this.extendRunResult(applyExtraRunFields(base, this.script));
4318
4382
  }
4319
4383
  /** Subclasses override to attach runtime-specific fields (e.g. cloud git info). */
@@ -4347,6 +4411,11 @@ function makeNotifier() {
4347
4411
  });
4348
4412
  return { promise, resolve: resolve3 };
4349
4413
  }
4414
+ function applyScriptMetrics(base, script) {
4415
+ if (script.usage !== void 0) base.usage = script.usage;
4416
+ if (script.cost !== void 0) base.cost = script.cost;
4417
+ if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
4418
+ }
4350
4419
 
4351
4420
  // src/internal/runtime/cloud/cloud-run.ts
4352
4421
  function createCloudRun(options) {
@@ -4855,6 +4924,18 @@ var CloudAgent = class {
4855
4924
  "fork"
4856
4925
  );
4857
4926
  }
4927
+ /**
4928
+ * The continuation driver re-sends against a stateful local session; the
4929
+ * cloud runtime manages its own continuation policy server-side (M1 Phase 3).
4930
+ *
4931
+ * @public
4932
+ */
4933
+ runToCompletion() {
4934
+ throw new UnsupportedRunOperationError(
4935
+ "Agent.runToCompletion() is not supported on cloud agents. Cloud runtime manages continuation server-side. Use a local agent.",
4936
+ "runToCompletion"
4937
+ );
4938
+ }
4858
4939
  /**
4859
4940
  * Personality presets require consistent server-side enforcement that
4860
4941
  * the cloud runtime (pre-release) does not yet provide. Reject explicitly
@@ -7979,6 +8060,9 @@ var LocalRun = class extends FixtureRunBase {
7979
8060
  }
7980
8061
  };
7981
8062
 
8063
+ // src/internal/runtime/local-agent/real-local-run.ts
8064
+ init_errors();
8065
+
7982
8066
  // src/internal/runtime/budget/budget.ts
7983
8067
  var IterationBudget = class {
7984
8068
  #remaining;
@@ -9203,6 +9287,7 @@ async function runAgentLoop(inputs) {
9203
9287
  const ctx = await initLoopContext(inputs);
9204
9288
  ctxRef = ctx;
9205
9289
  const budget = inputs.budget ?? new IterationBudget({ maxIterations: inputs.maxIterations ?? 8 });
9290
+ let lastTurnDecision;
9206
9291
  while (budget.shouldContinue()) {
9207
9292
  if (inputs.budgetTracker !== void 0) {
9208
9293
  const decision2 = evaluateBudgetGate(inputs.budgetTracker);
@@ -9211,18 +9296,26 @@ async function runAgentLoop(inputs) {
9211
9296
  if (decision2.detail !== void 0) {
9212
9297
  ctx.error = { message: decision2.detail, code: decision2.reason ?? "budget" };
9213
9298
  }
9299
+ if (decision2.reason === "iteration_limit") {
9300
+ ctx.stoppedAtIterationLimit = true;
9301
+ }
9214
9302
  break;
9215
9303
  }
9216
9304
  }
9217
9305
  const usingGrace = budget.remaining <= 0 && !budget.graceCallUsed;
9218
9306
  if (usingGrace) budget.useGraceCall();
9219
9307
  const decision = await runIteration(inputs, ctx);
9308
+ lastTurnDecision = decision;
9220
9309
  if (decision === "done") break;
9221
9310
  if (decision === "error") {
9222
9311
  ctx.finalStatus = "error";
9223
9312
  break;
9224
9313
  }
9225
9314
  budget.consume();
9315
+ inputs.budgetTracker?.nextIteration?.();
9316
+ }
9317
+ if (lastTurnDecision === "continue" && budget.shouldContinue() === false) {
9318
+ ctx.stoppedAtIterationLimit = true;
9226
9319
  }
9227
9320
  if (budget.shouldContinue() === false && ctx.finalStatus === "finished" && ctx.finalText === "") {
9228
9321
  ctx.finalStatus = "error";
@@ -9253,7 +9346,8 @@ async function runAgentLoop(inputs) {
9253
9346
  conversation: ctx.conversation,
9254
9347
  ...usage !== void 0 ? { usage } : {},
9255
9348
  ...cost !== void 0 ? { cost } : {},
9256
- ...ctx.error !== void 0 ? { error: ctx.error } : {}
9349
+ ...ctx.error !== void 0 ? { error: ctx.error } : {},
9350
+ ...ctx.stoppedAtIterationLimit === true ? { stoppedAtIterationLimit: true } : {}
9257
9351
  };
9258
9352
  } finally {
9259
9353
  if (ctxRef !== void 0 && ctxRef.memoryProviderHandle !== void 0 && inputs.memoryProvider !== void 0) {
@@ -11672,6 +11766,13 @@ function resolveRunProvider(options) {
11672
11766
  return { primary, effectiveModelId };
11673
11767
  }
11674
11768
  function buildLoopInputs(options, runId, userText) {
11769
+ const maxIterations = options.sendOptions.maxIterations;
11770
+ if (maxIterations !== void 0 && (!Number.isInteger(maxIterations) || maxIterations < 1)) {
11771
+ throw new ConfigurationError(
11772
+ `SendOptions.maxIterations must be a positive integer, got ${maxIterations}`,
11773
+ { code: "invalid_max_iterations" }
11774
+ );
11775
+ }
11675
11776
  const { primary, effectiveModelId } = resolveRunProvider(options);
11676
11777
  const fallback = options.agentOptions.providers?.fallback;
11677
11778
  const apiKeys = options.agentOptions.providers?.apiKeys;
@@ -11710,6 +11811,9 @@ function buildLoopInputs(options, runId, userText) {
11710
11811
  // D318 — forward SendOptions.signal to the agent loop so streamLlmTurn
11711
11812
  // can attach it to the LLM `fetch({ signal })` call.
11712
11813
  ...options.sendOptions.signal !== void 0 ? { signal: options.sendOptions.signal } : {},
11814
+ // M1-2: per-send iteration ceiling (validated above). The loop reads
11815
+ // inputs.maxIterations (default 8 when unset).
11816
+ ...maxIterations !== void 0 ? { maxIterations } : {},
11713
11817
  // D315-D317 — tool lifecycle hooks (cost tracking + audit + retry/alert)
11714
11818
  ...options.agentOptions.onToolStart !== void 0 ? { onToolStart: options.agentOptions.onToolStart } : {},
11715
11819
  ...options.agentOptions.onToolEnd !== void 0 ? { onToolEnd: options.agentOptions.onToolEnd } : {},
@@ -11841,6 +11945,7 @@ var RealLocalRun = class extends FixtureRunBase {
11841
11945
  if (output.result.length > 0) this.script.result = output.result;
11842
11946
  if (output.usage !== void 0) this.script.usage = output.usage;
11843
11947
  if (output.cost !== void 0) this.script.cost = output.cost;
11948
+ if (output.stoppedAtIterationLimit === true) this.script.stoppedAtIterationLimit = true;
11844
11949
  if (output.error !== void 0 && this.script.errorDetail === void 0) {
11845
11950
  this.script.errorDetail = {
11846
11951
  message: output.error.message,
@@ -14311,6 +14416,13 @@ function localAgentRunUntil(agent, goal, options) {
14311
14416
  }
14312
14417
  return wrap();
14313
14418
  }
14419
+ function localAgentRunToCompletion(agent, message, options) {
14420
+ async function run() {
14421
+ const { runToCompletionImpl: runToCompletionImpl2 } = await Promise.resolve().then(() => (init_run_to_completion(), run_to_completion_exports));
14422
+ return runToCompletionImpl2({ send: (m, o) => agent.send(m, o) }, message, options);
14423
+ }
14424
+ return run();
14425
+ }
14314
14426
  async function localAgentFork(parent, options) {
14315
14427
  const { forkAgentImpl: forkAgentImpl2 } = await Promise.resolve().then(() => (init_fork_agent(), fork_agent_exports));
14316
14428
  const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
@@ -14851,6 +14963,10 @@ var LocalAgent = class {
14851
14963
  fork(options) {
14852
14964
  return localAgentFork({ agentId: this.agentId, options: this.options, personalitySlugSnapshot: this.personalityStore.active(this.agentId) }, options);
14853
14965
  }
14966
+ // biome-ignore format: G8 budget — see runUntil comment above.
14967
+ runToCompletion(message, options) {
14968
+ return localAgentRunToCompletion(this, message, options);
14969
+ }
14854
14970
  };
14855
14971
  function resolveCwd(cwd) {
14856
14972
  return (Array.isArray(cwd) ? cwd[0] : cwd) ?? process.cwd();