@theokit/sdk 2.28.0 → 2.30.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/a2a/index.cjs +373 -17
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +373 -17
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/{cron-BR1NCSk1.d.cts → cron-BNHJywtl.d.ts} +482 -18
  7. package/dist/{cron-DgEQCJ2i.d.ts → cron-t4oKI2Is.d.cts} +482 -18
  8. package/dist/cron.cjs +1143 -692
  9. package/dist/cron.cjs.map +1 -1
  10. package/dist/cron.d.cts +2 -2
  11. package/dist/cron.d.ts +2 -2
  12. package/dist/cron.js +1146 -695
  13. package/dist/cron.js.map +1 -1
  14. package/dist/{errors-DLMNb4Ka.d.cts → errors-DZpCGlYv.d.cts} +1 -1
  15. package/dist/{errors-CbY3pxY7.d.ts → errors-D_Bfo30u.d.ts} +1 -1
  16. package/dist/errors.d.cts +2 -2
  17. package/dist/eval.cjs +914 -508
  18. package/dist/eval.cjs.map +1 -1
  19. package/dist/eval.js +915 -509
  20. package/dist/eval.js.map +1 -1
  21. package/dist/index.cjs +1038 -590
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +13 -135
  24. package/dist/index.d.ts +13 -135
  25. package/dist/index.js +1037 -588
  26. package/dist/index.js.map +1 -1
  27. package/dist/internal/persistence/conversation-storage-fs.d.cts +4 -0
  28. package/dist/internal/persistence/conversation-storage-fs.d.ts +4 -0
  29. package/dist/internal/persistence/conversation-storage-memory.d.cts +4 -0
  30. package/dist/internal/persistence/conversation-storage-memory.d.ts +4 -0
  31. package/dist/internal/persistence/objective-coerce.d.cts +9 -0
  32. package/dist/internal/persistence/objective-coerce.d.ts +9 -0
  33. package/dist/internal/runtime/lifecycle/wrap-completion-check-run.d.ts +30 -0
  34. package/dist/internal/runtime/local-agent/local-agent-goal-extensions.d.ts +80 -0
  35. package/dist/internal/runtime/objective/objective-store.d.ts +33 -0
  36. package/dist/{run-CdWiihyU.d.cts → run-CLXKMRgq.d.cts} +71 -2
  37. package/dist/{run-CdWiihyU.d.ts → run-CLXKMRgq.d.ts} +71 -2
  38. package/dist/types/agent.d.ts +32 -1
  39. package/dist/types/conversation-storage.d.ts +23 -0
  40. package/dist/types/cron.d.ts +30 -13
  41. package/dist/types/goal-events.d.ts +7 -0
  42. package/dist/types/index.d.ts +1 -0
  43. package/dist/types/objective.d.ts +45 -0
  44. package/dist/types/run-events.d.ts +12 -1
  45. package/dist/types/run.d.ts +58 -0
  46. package/package.json +3 -3
package/dist/a2a/index.js CHANGED
@@ -1365,7 +1365,7 @@ function safeFilenameForId(id, options) {
1365
1365
  code: "invalid_filename_id"
1366
1366
  });
1367
1367
  }
1368
- const maxLen = options?.maxLen;
1368
+ const maxLen = options?.maxLen ?? 128;
1369
1369
  const lower = id.toLowerCase();
1370
1370
  if (lower.length <= maxLen && IDENTIFIER_PATTERN.test(lower)) {
1371
1371
  return lower;
@@ -5112,6 +5112,40 @@ var init_agent_session_store = __esm({
5112
5112
  }
5113
5113
  });
5114
5114
 
5115
+ // src/internal/persistence/objective-coerce.ts
5116
+ function coerceOptions(raw) {
5117
+ if (typeof raw !== "object" || raw === null) return void 0;
5118
+ const o = raw;
5119
+ const out = {};
5120
+ if (typeof o.maxRuns === "number") out.maxRuns = o.maxRuns;
5121
+ if (typeof o.judgeModel === "string") out.judgeModel = o.judgeModel;
5122
+ if (typeof o.prompt === "string") out.prompt = o.prompt;
5123
+ return Object.keys(out).length > 0 ? out : void 0;
5124
+ }
5125
+ function coerceObjectiveRecord(raw) {
5126
+ if (typeof raw !== "object" || raw === null) return void 0;
5127
+ const o = raw;
5128
+ if (o._schemaVersion !== 1) return void 0;
5129
+ if (typeof o.objective !== "string") return void 0;
5130
+ if (typeof o.runsUsed !== "number") return void 0;
5131
+ if (typeof o.status !== "string" || !STATUSES.includes(o.status))
5132
+ return void 0;
5133
+ const options = coerceOptions(o.options);
5134
+ return {
5135
+ _schemaVersion: 1,
5136
+ objective: o.objective,
5137
+ ...options !== void 0 ? { options } : {},
5138
+ status: o.status,
5139
+ runsUsed: o.runsUsed
5140
+ };
5141
+ }
5142
+ var STATUSES;
5143
+ var init_objective_coerce = __esm({
5144
+ "src/internal/persistence/objective-coerce.ts"() {
5145
+ STATUSES = ["active", "done", "paused"];
5146
+ }
5147
+ });
5148
+
5115
5149
  // src/internal/persistence/pagination.ts
5116
5150
  function paginate(items, opts) {
5117
5151
  if (opts === void 0 || opts.offset === void 0 && opts.limit === void 0) return items;
@@ -5162,7 +5196,9 @@ var init_conversation_storage_fs = __esm({
5162
5196
  "src/internal/persistence/conversation-storage-fs.ts"() {
5163
5197
  init_agent_session_store();
5164
5198
  init_security();
5199
+ init_path_guard();
5165
5200
  init_file_lock();
5201
+ init_objective_coerce();
5166
5202
  init_pagination();
5167
5203
  init_session_meta();
5168
5204
  FileSystemConversationStorage = class {
@@ -5245,6 +5281,59 @@ var init_conversation_storage_fs = __esm({
5245
5281
  await writeFile(metaPath, redactSecrets(JSON.stringify(next)), "utf8");
5246
5282
  });
5247
5283
  }
5284
+ // SE33 — the durable objective is kept in `objective.json` beside the
5285
+ // transcript (separate from messages.jsonl + session.json). Uses the TOTAL
5286
+ // `safeFilenameForId` (not `sanitizeIdentifier`) so a caller-supplied
5287
+ // `threadId` with exotic characters (e.g. "user@example.com") hashes to a
5288
+ // deterministic dir instead of throwing — honoring the objective methods'
5289
+ // never-throw contract (ADR D6). Conforming ids pass through unchanged, so
5290
+ // the objective still sits beside the transcript for the normal case.
5291
+ #objectivePath(conversationId) {
5292
+ const safe2 = safeFilenameForId(conversationId, { maxLen: 128 });
5293
+ return safePathJoin(this.#root, ".theokit", "agents", safe2, "objective.json");
5294
+ }
5295
+ async getObjectiveRecord(conversationId) {
5296
+ try {
5297
+ const raw = await readFile(this.#objectivePath(conversationId), "utf8");
5298
+ return coerceObjectiveRecord(JSON.parse(raw));
5299
+ } catch (cause) {
5300
+ if (cause.code === "ENOENT") return void 0;
5301
+ throw cause;
5302
+ }
5303
+ }
5304
+ async setObjectiveRecord(conversationId, record) {
5305
+ const path = this.#objectivePath(conversationId);
5306
+ if (record === null) {
5307
+ await rm(path, { force: true });
5308
+ return;
5309
+ }
5310
+ await mkdir(dirname(path), { recursive: true });
5311
+ await withFileLock(path, async () => {
5312
+ await writeFile(path, redactSecrets(JSON.stringify(record)), "utf8");
5313
+ });
5314
+ }
5315
+ // SE33 (HIGH-1 fix) — atomic read-modify-write: the read that feeds `mutate`
5316
+ // happens INSIDE the same file lock as the write, so two concurrent progress
5317
+ // write-backs on one thread cannot both read a stale `runsUsed` and drop turns.
5318
+ async updateObjectiveRecord(conversationId, mutate) {
5319
+ const path = this.#objectivePath(conversationId);
5320
+ await mkdir(dirname(path), { recursive: true });
5321
+ await withFileLock(path, async () => {
5322
+ let current;
5323
+ try {
5324
+ current = coerceObjectiveRecord(JSON.parse(await readFile(path, "utf8")));
5325
+ } catch (cause) {
5326
+ if (cause.code !== "ENOENT") throw cause;
5327
+ }
5328
+ const next = mutate(current);
5329
+ if (next === void 0) return;
5330
+ if (next === null) {
5331
+ await rm(path, { force: true });
5332
+ return;
5333
+ }
5334
+ await writeFile(path, redactSecrets(JSON.stringify(next)), "utf8");
5335
+ });
5336
+ }
5248
5337
  async dispose() {
5249
5338
  }
5250
5339
  };
@@ -13279,6 +13368,151 @@ var init_local_agent_dispatch = __esm({
13279
13368
  }
13280
13369
  });
13281
13370
 
13371
+ // src/internal/runtime/objective/objective-store.ts
13372
+ function canPersist(a) {
13373
+ return typeof a.getObjectiveRecord === "function" && typeof a.setObjectiveRecord === "function";
13374
+ }
13375
+ async function mutateObjective(adapter, conversationId, mutate) {
13376
+ if (typeof adapter.updateObjectiveRecord === "function") {
13377
+ await adapter.updateObjectiveRecord(conversationId, mutate);
13378
+ return;
13379
+ }
13380
+ const current = await adapter.getObjectiveRecord(conversationId);
13381
+ const next = mutate(current);
13382
+ if (next === void 0) return;
13383
+ await adapter.setObjectiveRecord(conversationId, next);
13384
+ }
13385
+ async function getObjective(adapter, conversationId) {
13386
+ if (!canPersist(adapter)) return void 0;
13387
+ return adapter.getObjectiveRecord(conversationId);
13388
+ }
13389
+ async function setObjective(adapter, conversationId, objective, options) {
13390
+ if (!canPersist(adapter)) return;
13391
+ const record = {
13392
+ _schemaVersion: 1,
13393
+ objective,
13394
+ ...options !== void 0 ? { options } : {},
13395
+ status: "active",
13396
+ runsUsed: 0
13397
+ };
13398
+ await adapter.setObjectiveRecord(conversationId, record);
13399
+ }
13400
+ async function updateObjectiveOptions(adapter, conversationId, patch) {
13401
+ if (!canPersist(adapter)) return;
13402
+ await mutateObjective(
13403
+ adapter,
13404
+ conversationId,
13405
+ (current) => current === void 0 ? void 0 : { ...current, options: { ...current.options, ...patch } }
13406
+ );
13407
+ }
13408
+ async function writeObjectiveProgress(adapter, conversationId, progress) {
13409
+ if (!canPersist(adapter)) return;
13410
+ await mutateObjective(
13411
+ adapter,
13412
+ conversationId,
13413
+ (current) => current === void 0 ? void 0 : { ...current, runsUsed: progress.runsUsed, status: progress.status }
13414
+ );
13415
+ }
13416
+ async function clearObjective(adapter, conversationId) {
13417
+ if (!canPersist(adapter)) return;
13418
+ await adapter.setObjectiveRecord(conversationId, null);
13419
+ }
13420
+ var init_objective_store = __esm({
13421
+ "src/internal/runtime/objective/objective-store.ts"() {
13422
+ }
13423
+ });
13424
+
13425
+ // src/internal/runtime/local-agent/local-agent-goal-extensions.ts
13426
+ var local_agent_goal_extensions_exports = {};
13427
+ __export(local_agent_goal_extensions_exports, {
13428
+ formatObjectiveProjection: () => formatObjectiveProjection,
13429
+ localAgentClearObjective: () => localAgentClearObjective,
13430
+ localAgentGetObjective: () => localAgentGetObjective,
13431
+ localAgentSetObjective: () => localAgentSetObjective,
13432
+ localAgentUpdateObjectiveOptions: () => localAgentUpdateObjectiveOptions,
13433
+ persistDurableProgress: () => persistDurableProgress,
13434
+ resolveCurrentObjectiveText: () => resolveCurrentObjectiveText,
13435
+ resolveDurableRun: () => resolveDurableRun
13436
+ });
13437
+ function resolveAdapter(handle) {
13438
+ return typeof handle === "string" ? new FileSystemConversationStorage({ root: handle }) : handle;
13439
+ }
13440
+ function assertValidGoalOptions(options) {
13441
+ if (options.maxRuns !== void 0 && (!Number.isInteger(options.maxRuns) || options.maxRuns <= 0)) {
13442
+ throw new ConfigurationError(`maxRuns must be a positive integer, got ${options.maxRuns}`, {
13443
+ code: "invalid_objective_max_runs"
13444
+ });
13445
+ }
13446
+ }
13447
+ async function localAgentSetObjective(handle, objective, opts) {
13448
+ const { threadId, ...options } = opts;
13449
+ assertValidGoalOptions(options);
13450
+ await setObjective(
13451
+ resolveAdapter(handle),
13452
+ threadId,
13453
+ objective,
13454
+ Object.keys(options).length > 0 ? options : void 0
13455
+ );
13456
+ }
13457
+ async function localAgentGetObjective(handle, opts) {
13458
+ return getObjective(resolveAdapter(handle), opts.threadId);
13459
+ }
13460
+ async function localAgentUpdateObjectiveOptions(handle, opts) {
13461
+ const { threadId, ...patch } = opts;
13462
+ assertValidGoalOptions(patch);
13463
+ await updateObjectiveOptions(resolveAdapter(handle), threadId, patch);
13464
+ }
13465
+ async function localAgentClearObjective(handle, opts) {
13466
+ await clearObjective(resolveAdapter(handle), opts.threadId);
13467
+ }
13468
+ async function resolveCurrentObjectiveText(handle, threadId) {
13469
+ const record = await getObjective(resolveAdapter(handle), threadId);
13470
+ return record?.status === "active" ? record.objective : void 0;
13471
+ }
13472
+ function formatObjectiveProjection(objective, assembled) {
13473
+ const signal = `<current-objective>
13474
+ ${objective}
13475
+ </current-objective>`;
13476
+ return assembled === void 0 || assembled.length === 0 ? signal : `${signal}
13477
+
13478
+ ${assembled}`;
13479
+ }
13480
+ async function resolveDurableRun(handle, goalConfig, threadId, callerOptions) {
13481
+ const record = await getObjective(resolveAdapter(handle), threadId);
13482
+ if (record === void 0) return { kind: "none" };
13483
+ const judgeModel = callerOptions?.judgeModel ?? record.options?.judgeModel ?? goalConfig?.judgeModel;
13484
+ if (judgeModel === void 0) return { kind: "inert" };
13485
+ const totalBudget = record.options?.maxRuns ?? goalConfig?.maxRuns ?? DEFAULT_MAX_RUNS;
13486
+ const remaining = Math.max(0, totalBudget - record.runsUsed);
13487
+ if (remaining === 0) return { kind: "exhausted" };
13488
+ const perCall = callerOptions?.maxTurns;
13489
+ const maxTurns = perCall !== void 0 ? Math.min(perCall, remaining) : remaining;
13490
+ return {
13491
+ kind: "run",
13492
+ goal: record.objective,
13493
+ options: { ...callerOptions, maxTurns, judgeModel }
13494
+ };
13495
+ }
13496
+ async function persistDurableProgress(handle, threadId, result) {
13497
+ const adapter = resolveAdapter(handle);
13498
+ const record = await getObjective(adapter, threadId);
13499
+ if (record === void 0) return;
13500
+ const status = result.status === "completed" ? "done" : result.status === "paused" ? "paused" : "active";
13501
+ await writeObjectiveProgress(adapter, threadId, {
13502
+ runsUsed: record.runsUsed + result.turnsUsed,
13503
+ status
13504
+ });
13505
+ }
13506
+ var DEFAULT_MAX_RUNS;
13507
+ var init_local_agent_goal_extensions = __esm({
13508
+ "src/internal/runtime/local-agent/local-agent-goal-extensions.ts"() {
13509
+ init_errors();
13510
+ init_conversation_storage_fs();
13511
+ init_objective_store();
13512
+ DEFAULT_MAX_RUNS = 20;
13513
+ }
13514
+ });
13515
+
13282
13516
  // src/internal/runtime/local-agent/local-agent-invalidate.ts
13283
13517
  async function applyDeferredInvalidation(agentId, pending, refresh) {
13284
13518
  process.stderr.write(
@@ -16281,16 +16515,49 @@ var init_fork_agent = __esm({
16281
16515
  });
16282
16516
 
16283
16517
  // src/internal/runtime/local-agent/local-agent-runtime-extensions.ts
16284
- function localAgentRunUntil(agent, goal, options) {
16518
+ function pausedReason(kind, threadId) {
16519
+ switch (kind) {
16520
+ case "none":
16521
+ return `no durable objective set for thread "${threadId}" \u2014 call setObjective() first`;
16522
+ case "inert":
16523
+ return `durable objective for thread "${threadId}" is inert \u2014 no judge resolved (set a judge to activate)`;
16524
+ case "exhausted":
16525
+ return `durable objective for thread "${threadId}" exhausted its run budget \u2014 raise maxRuns to resume`;
16526
+ }
16527
+ }
16528
+ function localAgentRunUntil(agent, goal, options, durable) {
16285
16529
  async function* wrap() {
16286
16530
  const { runUntilImpl: runUntilImpl2 } = await Promise.resolve().then(() => (init_run_until(), run_until_exports));
16287
- const { judgeCallImpl: judgeCallImpl2 } = await Promise.resolve().then(() => (init_judge_call(), judge_call_exports));
16288
- const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
16289
- const create = getAgentFacade2().create;
16290
- const deps = {
16291
- judge: async (ctx, opts) => judgeCallImpl2(ctx, opts, { create })
16531
+ const buildDeps = async () => {
16532
+ const { judgeCallImpl: judgeCallImpl2 } = await Promise.resolve().then(() => (init_judge_call(), judge_call_exports));
16533
+ const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
16534
+ const create = getAgentFacade2().create;
16535
+ return {
16536
+ judge: (ctx, opts) => judgeCallImpl2(ctx, opts, { create })
16537
+ };
16292
16538
  };
16293
- return yield* runUntilImpl2(agent, goal, options, deps);
16539
+ if (goal !== void 0) {
16540
+ return yield* runUntilImpl2(agent, goal, options, await buildDeps());
16541
+ }
16542
+ const threadId = options?.threadId;
16543
+ if (durable === void 0 || threadId === void 0) {
16544
+ const reason = "runUntil() called with no goal and no threadId \u2014 nothing to resolve a durable objective from";
16545
+ yield { type: "status_change", status: "paused", reason };
16546
+ return { status: "paused", turnsUsed: 0, finalResponse: void 0 };
16547
+ }
16548
+ const { resolveDurableRun: resolveDurableRun2, persistDurableProgress: persistDurableProgress2 } = await Promise.resolve().then(() => (init_local_agent_goal_extensions(), local_agent_goal_extensions_exports));
16549
+ const resolved = await resolveDurableRun2(durable.handle, durable.goalConfig, threadId, options);
16550
+ if (resolved.kind !== "run") {
16551
+ yield {
16552
+ type: "status_change",
16553
+ status: "paused",
16554
+ reason: pausedReason(resolved.kind, threadId)
16555
+ };
16556
+ return { status: "paused", turnsUsed: 0, finalResponse: void 0 };
16557
+ }
16558
+ const result = yield* runUntilImpl2(agent, resolved.goal, resolved.options, await buildDeps());
16559
+ await persistDurableProgress2(durable.handle, threadId, result);
16560
+ return result;
16294
16561
  }
16295
16562
  return wrap();
16296
16563
  }
@@ -16363,6 +16630,49 @@ var init_abort_utils = __esm({
16363
16630
  }
16364
16631
  });
16365
16632
 
16633
+ // src/internal/runtime/lifecycle/wrap-completion-check-run.ts
16634
+ function wrapRunWithCompletionCheck(args) {
16635
+ const check = args.completionCheck;
16636
+ if (check === void 0) return args.run;
16637
+ const compute = async () => {
16638
+ const result = await args.run.wait();
16639
+ if (result.status !== "finished" || result.result === void 0) return result;
16640
+ const judgeOpts = {};
16641
+ if (check.judgeModel !== void 0) judgeOpts.judgeModel = check.judgeModel;
16642
+ if (check.apiKey !== void 0) judgeOpts.apiKey = check.apiKey;
16643
+ const verdict = await args.deps.judge(
16644
+ { goal: check.criteria, lastResponse: result.result },
16645
+ judgeOpts
16646
+ );
16647
+ const complete = !verdict.parseFailed && verdict.verdict === "done";
16648
+ emitRunEvent(args.onRunEvent, {
16649
+ type: "completion_check",
16650
+ complete,
16651
+ reason: verdict.reason
16652
+ });
16653
+ return {
16654
+ ...result,
16655
+ completionCheck: { complete, reason: verdict.reason, parseFailed: verdict.parseFailed }
16656
+ };
16657
+ };
16658
+ let judged;
16659
+ const wrappedWait = () => {
16660
+ judged ??= compute();
16661
+ return judged;
16662
+ };
16663
+ return new Proxy(args.run, {
16664
+ get(target, prop, receiver) {
16665
+ if (prop === "wait") return wrappedWait;
16666
+ return Reflect.get(target, prop, receiver);
16667
+ }
16668
+ });
16669
+ }
16670
+ var init_wrap_completion_check_run = __esm({
16671
+ "src/internal/runtime/lifecycle/wrap-completion-check-run.ts"() {
16672
+ init_run_events();
16673
+ }
16674
+ });
16675
+
16366
16676
  // src/internal/runtime/processors/run-processors.ts
16367
16677
  function fireViolation(processor, violation) {
16368
16678
  try {
@@ -16639,6 +16949,11 @@ async function executeSendLocked(inputs, message, options) {
16639
16949
  memoryFacts,
16640
16950
  activeMemorySummary
16641
16951
  );
16952
+ const projectedSystemPrompt = await projectCurrentObjective(
16953
+ inputs.storageHandle,
16954
+ options.objectiveThreadId,
16955
+ assembledSystemPrompt
16956
+ );
16642
16957
  const composedOptions = {
16643
16958
  ...options,
16644
16959
  signal: anySignal([options.signal, inputs.lifecycleAbortController.signal])
@@ -16646,7 +16961,7 @@ async function executeSendLocked(inputs, message, options) {
16646
16961
  const run = await inputs.dispatchRun(
16647
16962
  adaptedMessage,
16648
16963
  composedOptions,
16649
- assembledSystemPrompt,
16964
+ projectedSystemPrompt,
16650
16965
  memoryFacts,
16651
16966
  priorMessages,
16652
16967
  memoryTools,
@@ -16659,23 +16974,49 @@ async function executeSendLocked(inputs, message, options) {
16659
16974
  agentId: inputs.agentId,
16660
16975
  onRunEvent: options.onRunEvent
16661
16976
  }) : run;
16662
- return wrapRunWithPostReplyHook({
16977
+ const hookedRun = wrapRunWithPostReplyHook({
16663
16978
  pluginManager: inputs.pluginManagerCode,
16664
16979
  agentId: inputs.agentId,
16665
16980
  options: inputs.options,
16666
16981
  run: processedRun,
16667
16982
  userText
16668
16983
  });
16984
+ return wrapRunWithCompletionCheck({
16985
+ run: hookedRun,
16986
+ completionCheck: options.completionCheck,
16987
+ onRunEvent: options.onRunEvent,
16988
+ deps: buildCompletionCheckDeps()
16989
+ });
16990
+ }
16991
+ function buildCompletionCheckDeps() {
16992
+ return {
16993
+ judge: async (ctx, opts) => {
16994
+ const { judgeCallImpl: judgeCallImpl2 } = await Promise.resolve().then(() => (init_judge_call(), judge_call_exports));
16995
+ const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
16996
+ return judgeCallImpl2(ctx, opts, { create: getAgentFacade2().create });
16997
+ }
16998
+ };
16669
16999
  }
16670
17000
  function readMemoryForSend(workspaceCwd, memoryConfig) {
16671
17001
  if (memoryConfig?.enabled !== true) return Promise.resolve([]);
16672
17002
  return safeCall(() => readMemoryFacts(workspaceCwd, memoryConfig), [], "memory read");
16673
17003
  }
17004
+ async function projectCurrentObjective(storageHandle, objectiveThreadId, assembled) {
17005
+ if (objectiveThreadId === void 0) return assembled;
17006
+ const objective = await safeCall(
17007
+ () => resolveCurrentObjectiveText(storageHandle, objectiveThreadId),
17008
+ void 0,
17009
+ "objective projection"
17010
+ );
17011
+ if (objective === void 0) return assembled;
17012
+ return formatObjectiveProjection(objective, assembled);
17013
+ }
16674
17014
  var init_local_agent_send = __esm({
16675
17015
  "src/internal/runtime/local-agent/local-agent-send.ts"() {
16676
17016
  init_errors();
16677
17017
  init_run_events();
16678
17018
  init_abort_utils();
17019
+ init_wrap_completion_check_run();
16679
17020
  init_memory_path_selector();
16680
17021
  init_memory_store();
16681
17022
  init_model_selection();
@@ -16684,6 +17025,7 @@ var init_local_agent_send = __esm({
16684
17025
  init_wrap_output_run();
16685
17026
  init_agent_session();
16686
17027
  init_safe_call();
17028
+ init_local_agent_goal_extensions();
16687
17029
  init_local_agent_invalidate();
16688
17030
  init_local_agent_memory_hooks();
16689
17031
  init_local_agent_runtime_extensions();
@@ -17283,6 +17625,7 @@ var init_local_agent = __esm({
17283
17625
  init_validate_agent_options();
17284
17626
  init_local_agent_bootstrap();
17285
17627
  init_local_agent_dispatch();
17628
+ init_local_agent_goal_extensions();
17286
17629
  init_local_agent_invalidate();
17287
17630
  init_local_agent_memory();
17288
17631
  init_local_agent_memory_direct();
@@ -17622,20 +17965,33 @@ var init_local_agent = __esm({
17622
17965
  ...opts !== void 0 ? { opts } : {}
17623
17966
  });
17624
17967
  }
17968
+ // biome-ignore format: G8 budget — artifact stubs (local agents have no artifacts); kept 1-line each.
17625
17969
  listArtifacts() {
17626
17970
  return Promise.resolve([]);
17627
17971
  }
17972
+ // biome-ignore format: G8 budget — see listArtifacts.
17628
17973
  downloadArtifact(_path) {
17629
- return Promise.reject(
17630
- new UnsupportedRunOperationError(
17631
- "Artifacts are not supported for local agents",
17632
- "downloadArtifact"
17633
- )
17634
- );
17974
+ return Promise.reject(new UnsupportedRunOperationError("Artifacts are not supported for local agents", "downloadArtifact"));
17635
17975
  }
17636
17976
  // biome-ignore format: G8 budget — both methods delegate to `local-agent-runtime-extensions.ts`; signatures kept as 1-line each.
17637
17977
  runUntil(goal, options) {
17638
- return localAgentRunUntil(this, goal, options);
17978
+ return localAgentRunUntil(this, goal, options, { handle: this.storageHandle(), goalConfig: this.options.goal });
17979
+ }
17980
+ // biome-ignore format: SE33 G8 budget — objective methods delegate to `local-agent-goal-extensions.ts`.
17981
+ setObjective(objective, opts) {
17982
+ return localAgentSetObjective(this.storageHandle(), objective, opts);
17983
+ }
17984
+ // biome-ignore format: SE33 G8 budget — see setObjective above.
17985
+ getObjective(opts) {
17986
+ return localAgentGetObjective(this.storageHandle(), opts);
17987
+ }
17988
+ // biome-ignore format: SE33 G8 budget — see setObjective above.
17989
+ updateObjectiveOptions(opts) {
17990
+ return localAgentUpdateObjectiveOptions(this.storageHandle(), opts);
17991
+ }
17992
+ // biome-ignore format: SE33 G8 budget — see setObjective above.
17993
+ clearObjective(opts) {
17994
+ return localAgentClearObjective(this.storageHandle(), opts);
17639
17995
  }
17640
17996
  // biome-ignore format: G8 budget — see runUntil comment above.
17641
17997
  fork(options) {