@theokit/sdk 4.17.1 → 4.18.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.
@@ -598,7 +598,7 @@ type GoalEvent = {
598
598
  prompt: string;
599
599
  } | {
600
600
  type: "status_change";
601
- status: "active" | "paused" | "completed" | "failed";
601
+ status: "active" | "paused" | "completed" | "failed" | "budget_limited" | "blocked";
602
602
  reason: string;
603
603
  };
604
604
  /**
@@ -608,8 +608,10 @@ type GoalEvent = {
608
608
  * @public
609
609
  */
610
610
  interface GoalResult {
611
- status: "completed" | "failed" | "paused";
611
+ status: "completed" | "failed" | "paused" | "budget_limited" | "blocked";
612
612
  turnsUsed: number;
613
+ /** M55 — tokens somados ao longo do loop (0 quando `usage` esteve ausente — fail-open). */
614
+ tokensUsed: number;
613
615
  finalResponse: string | undefined;
614
616
  }
615
617
  /**
@@ -625,8 +627,14 @@ type RunUntilIterator = AsyncGenerator<GoalEvent, GoalResult, void>;
625
627
  * @public
626
628
  */
627
629
  interface GoalOptions {
628
- /** Hard cap on iterations. Default `20`. */
630
+ /** Hard cap on iterations (safety net against runaway). Default `20`. */
629
631
  maxTurns?: number;
632
+ /**
633
+ * M55 — token budget (Codex ext/goal parity, tool.rs:454-465). Soma `run.wait().usage.totalTokens`
634
+ * por turno; ao cruzar, o loop para com status `budget_limited`. Omitido ⇒ ilimitado (só maxTurns).
635
+ * `usage` ausente nunca estoura o budget (fail-open).
636
+ */
637
+ tokenBudget?: number;
630
638
  /** Bail after N consecutive judge parse failures. Default `3` (ADR D121). */
631
639
  maxConsecutiveJudgeFailures?: number;
632
640
  /** Judge model identifier. Default `"openai/gpt-4o-mini"` (ADR D119). */
@@ -598,7 +598,7 @@ type GoalEvent = {
598
598
  prompt: string;
599
599
  } | {
600
600
  type: "status_change";
601
- status: "active" | "paused" | "completed" | "failed";
601
+ status: "active" | "paused" | "completed" | "failed" | "budget_limited" | "blocked";
602
602
  reason: string;
603
603
  };
604
604
  /**
@@ -608,8 +608,10 @@ type GoalEvent = {
608
608
  * @public
609
609
  */
610
610
  interface GoalResult {
611
- status: "completed" | "failed" | "paused";
611
+ status: "completed" | "failed" | "paused" | "budget_limited" | "blocked";
612
612
  turnsUsed: number;
613
+ /** M55 — tokens somados ao longo do loop (0 quando `usage` esteve ausente — fail-open). */
614
+ tokensUsed: number;
613
615
  finalResponse: string | undefined;
614
616
  }
615
617
  /**
@@ -625,8 +627,14 @@ type RunUntilIterator = AsyncGenerator<GoalEvent, GoalResult, void>;
625
627
  * @public
626
628
  */
627
629
  interface GoalOptions {
628
- /** Hard cap on iterations. Default `20`. */
630
+ /** Hard cap on iterations (safety net against runaway). Default `20`. */
629
631
  maxTurns?: number;
632
+ /**
633
+ * M55 — token budget (Codex ext/goal parity, tool.rs:454-465). Soma `run.wait().usage.totalTokens`
634
+ * por turno; ao cruzar, o loop para com status `budget_limited`. Omitido ⇒ ilimitado (só maxTurns).
635
+ * `usage` ausente nunca estoura o budget (fail-open).
636
+ */
637
+ tokenBudget?: number;
630
638
  /** Bail after N consecutive judge parse failures. Default `3` (ADR D121). */
631
639
  maxConsecutiveJudgeFailures?: number;
632
640
  /** Judge model identifier. Default `"openai/gpt-4o-mini"` (ADR D119). */
package/dist/cron.cjs CHANGED
@@ -6256,10 +6256,12 @@ __export(run_until_exports, {
6256
6256
  async function* runUntilImpl(agent, goal, options, deps) {
6257
6257
  const maxTurns = options?.maxTurns ?? 20;
6258
6258
  const maxFails = options?.maxConsecutiveJudgeFailures ?? 3;
6259
+ const tokenBudget = options?.tokenBudget;
6259
6260
  const signal = options?.signal;
6260
6261
  const isAborted = () => signal !== void 0 && signal.aborted;
6261
6262
  let turn = 0;
6262
6263
  let consecutiveFailures = 0;
6264
+ let tokensUsed = 0;
6263
6265
  let lastResponse = "";
6264
6266
  if (isAborted()) {
6265
6267
  yield {
@@ -6267,13 +6269,13 @@ async function* runUntilImpl(agent, goal, options, deps) {
6267
6269
  status: "paused",
6268
6270
  reason: "aborted via AbortSignal before first turn"
6269
6271
  };
6270
- return { status: "paused", turnsUsed: 0, finalResponse: void 0 };
6272
+ return { status: "paused", turnsUsed: 0, tokensUsed, finalResponse: void 0 };
6271
6273
  }
6272
6274
  yield { type: "status_change", status: "active", reason: "Goal started" };
6273
6275
  while (turn < maxTurns) {
6274
6276
  if (isAborted()) {
6275
6277
  yield { type: "status_change", status: "paused", reason: "aborted via AbortSignal" };
6276
- return { status: "paused", turnsUsed: turn, finalResponse: lastResponse || void 0 };
6278
+ return { status: "paused", turnsUsed: turn, tokensUsed, finalResponse: lastResponse || void 0 };
6277
6279
  }
6278
6280
  turn += 1;
6279
6281
  yield { type: "turn_start", turn, goal };
@@ -6281,6 +6283,8 @@ async function* runUntilImpl(agent, goal, options, deps) {
6281
6283
  const run = await agent.send(continuationPrompt);
6282
6284
  const result = await run.wait();
6283
6285
  lastResponse = result.result ?? "";
6286
+ const turnTokens = result.usage?.totalTokens;
6287
+ if (typeof turnTokens === "number") tokensUsed += turnTokens;
6284
6288
  yield { type: "agent_response", turn, content: lastResponse };
6285
6289
  const judgeOpts = {};
6286
6290
  if (options?.judgeModel !== void 0) judgeOpts.judgeModel = options.judgeModel;
@@ -6306,6 +6310,7 @@ async function* runUntilImpl(agent, goal, options, deps) {
6306
6310
  return {
6307
6311
  status: "failed",
6308
6312
  turnsUsed: turn,
6313
+ tokensUsed,
6309
6314
  finalResponse: lastResponse || void 0
6310
6315
  };
6311
6316
  }
@@ -6314,7 +6319,7 @@ async function* runUntilImpl(agent, goal, options, deps) {
6314
6319
  }
6315
6320
  if (judgment.verdict === "done") {
6316
6321
  yield { type: "status_change", status: "completed", reason: judgment.reason };
6317
- return { status: "completed", turnsUsed: turn, finalResponse: lastResponse || void 0 };
6322
+ return { status: "completed", turnsUsed: turn, tokensUsed, finalResponse: lastResponse || void 0 };
6318
6323
  }
6319
6324
  if (judgment.verdict === "skipped") {
6320
6325
  yield {
@@ -6322,7 +6327,15 @@ async function* runUntilImpl(agent, goal, options, deps) {
6322
6327
  status: "completed",
6323
6328
  reason: `skipped: ${judgment.reason}`
6324
6329
  };
6325
- return { status: "completed", turnsUsed: turn, finalResponse: lastResponse || void 0 };
6330
+ return { status: "completed", turnsUsed: turn, tokensUsed, finalResponse: lastResponse || void 0 };
6331
+ }
6332
+ if (tokenBudget !== void 0 && tokensUsed >= tokenBudget) {
6333
+ yield {
6334
+ type: "status_change",
6335
+ status: "budget_limited",
6336
+ reason: `token budget (${tokenBudget}) reached: ${tokensUsed} used`
6337
+ };
6338
+ return { status: "budget_limited", turnsUsed: turn, tokensUsed, finalResponse: lastResponse || void 0 };
6326
6339
  }
6327
6340
  yield { type: "continuation", turn, prompt: continuationPrompt };
6328
6341
  }
@@ -6331,13 +6344,32 @@ async function* runUntilImpl(agent, goal, options, deps) {
6331
6344
  status: "failed",
6332
6345
  reason: `max turns (${maxTurns}) exhausted`
6333
6346
  };
6334
- return { status: "failed", turnsUsed: turn, finalResponse: lastResponse || void 0 };
6347
+ return { status: "failed", turnsUsed: turn, tokensUsed, finalResponse: lastResponse || void 0 };
6335
6348
  }
6336
6349
  function composeContinuation(goal, lastResponse) {
6337
- return `Continue working toward the goal: ${goal}
6338
-
6339
- Your last response was:
6340
- ${lastResponse.slice(0, 1e3)}`;
6350
+ return [
6351
+ "Continue working toward the active goal.",
6352
+ "",
6353
+ `<objective>
6354
+ ${goal}
6355
+ </objective>`,
6356
+ "",
6357
+ "Continuation behavior:",
6358
+ "- This goal persists across turns. Keep the full objective intact; if it cannot be finished now,",
6359
+ " make concrete progress toward the real requested end state and do not redefine success around a",
6360
+ " smaller or easier task.",
6361
+ "",
6362
+ "Work from evidence:",
6363
+ "- Use the current worktree and external state as authoritative. Inspect the current state before",
6364
+ " relying on it. Improve, replace, or remove existing work as needed to satisfy the actual objective.",
6365
+ "",
6366
+ "Completion audit:",
6367
+ "- Before deciding the goal is achieved, treat completion as unproven and verify it against the actual",
6368
+ " current state, requirement by requirement. Treat uncertain or indirect evidence as not achieved.",
6369
+ "",
6370
+ `Your last response was:
6371
+ ${lastResponse.slice(0, 1e3)}`
6372
+ ].join("\n");
6341
6373
  }
6342
6374
  var init_run_until = __esm({
6343
6375
  "src/internal/runtime/lifecycle/run-until.ts"() {
@@ -18581,7 +18613,7 @@ function localAgentRunUntil(agent, goal, options) {
18581
18613
  status: "paused",
18582
18614
  reason: "runUntil() requires an explicit goal (durable objectives removed in v4.0)"
18583
18615
  };
18584
- return { status: "paused", turnsUsed: 0, finalResponse: void 0 };
18616
+ return { status: "paused", turnsUsed: 0, tokensUsed: 0, finalResponse: void 0 };
18585
18617
  }
18586
18618
  return yield* runUntilImpl2(agent, goal, options, await buildDeps());
18587
18619
  }