@theokit/sdk 2.20.0 → 2.22.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 (92) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/dist/a2a/index.cjs +673 -317
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.d.cts +2 -1
  5. package/dist/a2a/index.d.ts +2 -1
  6. package/dist/a2a/index.js +674 -318
  7. package/dist/a2a/index.js.map +1 -1
  8. package/dist/a2a/subagent.d.cts +70 -1
  9. package/dist/a2a/subagent.d.ts +70 -1
  10. package/dist/a2a/types.d.cts +7 -0
  11. package/dist/a2a/types.d.ts +7 -0
  12. package/dist/agent-builder.d.ts +2 -1
  13. package/dist/agent-generate.d.ts +12 -0
  14. package/dist/client/index.cjs.map +1 -1
  15. package/dist/client/index.d.cts +5 -0
  16. package/dist/client/index.d.ts +5 -0
  17. package/dist/client/index.js.map +1 -1
  18. package/dist/client/theokit-client.d.cts +6 -0
  19. package/dist/client/theokit-client.d.ts +6 -0
  20. package/dist/client/types.d.cts +2 -0
  21. package/dist/client/types.d.ts +2 -0
  22. package/dist/{cron-B8fqui49.d.cts → cron-7CruUd_0.d.ts} +53 -3
  23. package/dist/{cron-D2yLOrk2.d.ts → cron-Bpt_1khA.d.cts} +53 -3
  24. package/dist/cron.cjs +654 -389
  25. package/dist/cron.cjs.map +1 -1
  26. package/dist/cron.d.cts +3 -2
  27. package/dist/cron.d.ts +3 -2
  28. package/dist/cron.js +655 -390
  29. package/dist/cron.js.map +1 -1
  30. package/dist/{errors-5lj1EWgs.d.ts → errors-BuwwkrAk.d.ts} +2 -2
  31. package/dist/{errors-CE-lMBi2.d.cts → errors-CkCaIqVP.d.cts} +2 -2
  32. package/dist/errors.d.cts +3 -2
  33. package/dist/eval.cjs +654 -389
  34. package/dist/eval.cjs.map +1 -1
  35. package/dist/eval.js +654 -389
  36. package/dist/eval.js.map +1 -1
  37. package/dist/generate-object.d.ts +4 -3
  38. package/dist/index.cjs +800 -392
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +259 -17
  41. package/dist/index.d.ts +259 -17
  42. package/dist/index.js +798 -394
  43. package/dist/index.js.map +1 -1
  44. package/dist/internal/agent-loop/loop-types.d.ts +2 -0
  45. package/dist/internal/agent-loop/tool-result-guard.d.ts +1 -0
  46. package/dist/internal/llm/tool-result-content.d.ts +40 -0
  47. package/dist/internal/llm/types.d.ts +6 -1
  48. package/dist/internal/persistence/conversation-storage-fs.d.cts +3 -1
  49. package/dist/internal/persistence/conversation-storage-fs.d.ts +3 -1
  50. package/dist/internal/persistence/conversation-storage-memory.d.cts +3 -1
  51. package/dist/internal/persistence/conversation-storage-memory.d.ts +3 -1
  52. package/dist/internal/persistence/session-meta.d.cts +13 -0
  53. package/dist/internal/persistence/session-meta.d.ts +13 -0
  54. package/dist/internal/runtime/model-selection.d.ts +14 -0
  55. package/dist/internal/structured-output-helpers.d.ts +1 -1
  56. package/dist/permission-engine.d.ts +32 -1
  57. package/dist/{run-BgfBWX-z.d.cts → run-CrIulPF7.d.cts} +282 -19
  58. package/dist/{run-BgfBWX-z.d.ts → run-CrIulPF7.d.ts} +282 -19
  59. package/dist/stream-object.d.ts +2 -1
  60. package/dist/tool-error.d.ts +30 -0
  61. package/dist/types/agent-prims.d.ts +30 -8
  62. package/dist/types/agent.d.ts +13 -2
  63. package/dist/types/content-blocks.d.ts +47 -0
  64. package/dist/types/conversation-storage.d.ts +38 -0
  65. package/dist/types/index.d.ts +1 -0
  66. package/dist/types/messages.d.ts +2 -9
  67. package/dist/types/run-events.d.ts +84 -0
  68. package/dist/types/run.d.ts +115 -1
  69. package/dist/types/session.d.ts +99 -0
  70. package/dist/types/workflow.d.ts +7 -0
  71. package/dist/workflow.cjs +7 -2
  72. package/dist/workflow.cjs.map +1 -1
  73. package/dist/workflow.d.cts +2 -0
  74. package/dist/workflow.d.ts +2 -0
  75. package/dist/workflow.js +7 -2
  76. package/dist/workflow.js.map +1 -1
  77. package/package.json +14 -34
  78. package/dist/internal/observability/context.d.cts +0 -23
  79. package/dist/internal/observability/context.d.ts +0 -23
  80. package/dist/internal/observability/index.cjs +0 -38
  81. package/dist/internal/observability/index.cjs.map +0 -1
  82. package/dist/internal/observability/index.d.cts +0 -8
  83. package/dist/internal/observability/index.d.ts +0 -8
  84. package/dist/internal/observability/index.js +0 -33
  85. package/dist/internal/observability/index.js.map +0 -1
  86. package/dist/internal/plugins/index.cjs +0 -363
  87. package/dist/internal/plugins/index.cjs.map +0 -1
  88. package/dist/internal/plugins/index.js +0 -357
  89. package/dist/internal/plugins/index.js.map +0 -1
  90. package/dist/internal/workflow/index.d.ts +0 -12
  91. package/dist/server/adapter/index.d.cts +0 -8
  92. package/dist/server/adapter/index.d.ts +0 -8
package/dist/eval.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var zod = require('zod');
4
+ var module$1 = require('module');
3
5
  var crypto = require('crypto');
4
6
  var promises = require('fs/promises');
5
7
  var path = require('path');
6
- var zod = require('zod');
7
8
  var fs = require('fs');
8
9
  var async_hooks = require('async_hooks');
9
- var module$1 = require('module');
10
10
  var os = require('os');
11
11
  var child_process = require('child_process');
12
12
  var url = require('url');
@@ -512,6 +512,256 @@ var init_errors = __esm({
512
512
  };
513
513
  }
514
514
  });
515
+ function toJsonSchema(schema, options = { unrepresentable: "any" }) {
516
+ return zod.toJSONSchema(schema, options);
517
+ }
518
+ var init_to_json_schema = __esm({
519
+ "src/internal/zod/to-json-schema.ts"() {
520
+ }
521
+ });
522
+ function requireZod() {
523
+ if (cachedZ !== void 0) return cachedZ;
524
+ const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('eval.cjs', document.baseURI).href)));
525
+ let mod;
526
+ try {
527
+ mod = r("zod");
528
+ } catch (cause) {
529
+ throw new ConfigurationError(
530
+ 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
531
+ { code: "zod_not_installed", cause }
532
+ );
533
+ }
534
+ cachedZ = mod.z ?? mod;
535
+ return cachedZ;
536
+ }
537
+ function makeOutputTool(jsonSchema, onCapture) {
538
+ return {
539
+ name: "output",
540
+ description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
541
+ inputSchema: jsonSchema,
542
+ handler: (input) => {
543
+ const out = onCapture(input);
544
+ if (typeof out === "string") return out;
545
+ if (out instanceof Promise) return out;
546
+ return "";
547
+ }
548
+ };
549
+ }
550
+ function buildTransientAgentOptions(params) {
551
+ return {
552
+ model: params.model,
553
+ local: params.local,
554
+ tools: [params.outputTool],
555
+ systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
556
+ ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
557
+ ...params.providers !== void 0 ? { providers: params.providers } : {}
558
+ };
559
+ }
560
+ function extractUsage(result) {
561
+ const u = result.usage;
562
+ if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
563
+ return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
564
+ }
565
+ function buildToolPrompt(prompt) {
566
+ return `${prompt}
567
+
568
+ Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
569
+ }
570
+ function setupStructuredOutput(schema, maxRetries) {
571
+ const z7 = requireZod();
572
+ const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
573
+ return {
574
+ z: z7,
575
+ jsonSchema,
576
+ maxRetries: maxRetries ?? 1,
577
+ initialUsage: { inputTokens: 0, outputTokens: 0 }
578
+ };
579
+ }
580
+ async function disposeAndDeleteTransient(agent, deletor) {
581
+ await agent.dispose();
582
+ try {
583
+ await deletor(agent.agentId);
584
+ } catch {
585
+ }
586
+ }
587
+ var cachedZ;
588
+ var init_structured_output_helpers = __esm({
589
+ "src/internal/structured-output-helpers.ts"() {
590
+ init_errors();
591
+ init_to_json_schema();
592
+ }
593
+ });
594
+
595
+ // src/generate-object.ts
596
+ var generate_object_exports = {};
597
+ __export(generate_object_exports, {
598
+ GenerateObjectError: () => GenerateObjectError,
599
+ generateObjectImpl: () => generateObjectImpl
600
+ });
601
+ function salvagePartial(schema, raw) {
602
+ if (typeof raw !== "object" || raw === null) return raw;
603
+ const shape = schema.shape;
604
+ if (shape === void 0 || typeof shape !== "object") return raw;
605
+ const rawObj = raw;
606
+ const out = {};
607
+ for (const [key, fieldSchema] of Object.entries(shape)) {
608
+ if (typeof fieldSchema?.safeParse !== "function") continue;
609
+ const parsed = fieldSchema.safeParse(rawObj[key]);
610
+ if (parsed.success) out[key] = parsed.data;
611
+ }
612
+ return out;
613
+ }
614
+ async function runReasoningPhase(options, deps) {
615
+ const reasoningOptions = {
616
+ model: options.model,
617
+ local: options.local,
618
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
619
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
620
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
621
+ };
622
+ const reasoningAgent = await deps.create(reasoningOptions);
623
+ try {
624
+ const run = await reasoningAgent.send(options.prompt);
625
+ const result = await run.wait();
626
+ const text = result.result;
627
+ return typeof text === "string" ? text : options.prompt;
628
+ } finally {
629
+ await disposeAndDeleteTransient(reasoningAgent, deps.delete);
630
+ }
631
+ }
632
+ async function generateObjectImpl(options, deps) {
633
+ const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
634
+ options.schema,
635
+ options.maxRetries
636
+ );
637
+ let capturedRaw;
638
+ let lastUsage = initialUsage;
639
+ const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
640
+ class CaptureSentinel extends Error {
641
+ constructor(captured) {
642
+ super("generate-object-capture");
643
+ this.captured = captured;
644
+ }
645
+ captured;
646
+ [sentinel] = true;
647
+ }
648
+ const outputTool = makeOutputTool(jsonSchema, (input) => {
649
+ if (capturedRaw === void 0) {
650
+ capturedRaw = input;
651
+ }
652
+ throw new CaptureSentinel(input);
653
+ });
654
+ const reasoningText = options.structuringModel !== void 0 ? await runReasoningPhase(options, deps) : void 0;
655
+ const structuringModel = options.structuringModel ?? options.model;
656
+ const structuringPrompt = reasoningText ?? options.prompt;
657
+ const agentOptions = buildTransientAgentOptions({
658
+ model: structuringModel,
659
+ local: options.local,
660
+ outputTool,
661
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
662
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
663
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
664
+ });
665
+ const agent = await deps.create(agentOptions);
666
+ try {
667
+ const userMessage = buildToolPrompt(structuringPrompt);
668
+ let lastParseError;
669
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
670
+ capturedRaw = void 0;
671
+ const run = await agent.send(userMessage);
672
+ const result = await run.wait();
673
+ lastUsage = extractUsage(result);
674
+ if (capturedRaw === void 0) {
675
+ if (result.status === "error" && result.error !== void 0) {
676
+ throw new GenerateObjectError(
677
+ "no_tool_call",
678
+ `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
679
+ result.error
680
+ );
681
+ }
682
+ if (attempt === maxRetries) {
683
+ throw new GenerateObjectError(
684
+ "no_tool_call",
685
+ "The model returned text instead of calling the `output` tool."
686
+ );
687
+ }
688
+ continue;
689
+ }
690
+ const parsed = options.schema.safeParse(capturedRaw);
691
+ if (parsed.success) {
692
+ return {
693
+ object: parsed.data,
694
+ raw: capturedRaw,
695
+ usage: lastUsage,
696
+ finishReason: "tool_use"
697
+ };
698
+ }
699
+ lastParseError = parsed.error;
700
+ }
701
+ if (options.errorStrategy === "return-raw") {
702
+ return {
703
+ object: capturedRaw,
704
+ raw: capturedRaw,
705
+ usage: lastUsage,
706
+ finishReason: "tool_use"
707
+ };
708
+ }
709
+ if (options.errorStrategy === "return-partial") {
710
+ return {
711
+ object: salvagePartial(options.schema, capturedRaw),
712
+ raw: capturedRaw,
713
+ usage: lastUsage,
714
+ finishReason: "tool_use"
715
+ };
716
+ }
717
+ throw new GenerateObjectError(
718
+ "parse_failed",
719
+ "Schema parse failed after all retries.",
720
+ lastParseError
721
+ );
722
+ } finally {
723
+ await disposeAndDeleteTransient(agent, deps.delete);
724
+ }
725
+ }
726
+ var GenerateObjectError;
727
+ var init_generate_object = __esm({
728
+ "src/generate-object.ts"() {
729
+ init_structured_output_helpers();
730
+ GenerateObjectError = class extends Error {
731
+ name = "GenerateObjectError";
732
+ code;
733
+ cause;
734
+ constructor(code, message, cause) {
735
+ super(message);
736
+ this.code = code;
737
+ if (cause !== void 0) this.cause = cause;
738
+ }
739
+ };
740
+ }
741
+ });
742
+
743
+ // src/internal/runtime/registry/agent-factory-registry.ts
744
+ var agent_factory_registry_exports = {};
745
+ __export(agent_factory_registry_exports, {
746
+ getAgentFacade: () => getAgentFacade,
747
+ setAgentFacade: () => setAgentFacade
748
+ });
749
+ function setAgentFacade(facade) {
750
+ registered = facade;
751
+ }
752
+ function getAgentFacade() {
753
+ if (registered === void 0) {
754
+ throw new Error(
755
+ "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
756
+ );
757
+ }
758
+ return registered;
759
+ }
760
+ var registered;
761
+ var init_agent_factory_registry = __esm({
762
+ "src/internal/runtime/registry/agent-factory-registry.ts"() {
763
+ }
764
+ });
515
765
 
516
766
  // src/internal/persistence/cwd-mutex.ts
517
767
  function withCwdMutex(key, fn) {
@@ -1429,29 +1679,6 @@ var init_judge_call = __esm({
1429
1679
  }
1430
1680
  });
1431
1681
 
1432
- // src/internal/runtime/registry/agent-factory-registry.ts
1433
- var agent_factory_registry_exports = {};
1434
- __export(agent_factory_registry_exports, {
1435
- getAgentFacade: () => getAgentFacade,
1436
- setAgentFacade: () => setAgentFacade
1437
- });
1438
- function setAgentFacade(facade) {
1439
- registered3 = facade;
1440
- }
1441
- function getAgentFacade() {
1442
- if (registered3 === void 0) {
1443
- throw new Error(
1444
- "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
1445
- );
1446
- }
1447
- return registered3;
1448
- }
1449
- var registered3;
1450
- var init_agent_factory_registry = __esm({
1451
- "src/internal/runtime/registry/agent-factory-registry.ts"() {
1452
- }
1453
- });
1454
-
1455
1682
  // src/internal/runtime/lifecycle/run-to-completion.ts
1456
1683
  var run_to_completion_exports = {};
1457
1684
  __export(run_to_completion_exports, {
@@ -1616,14 +1843,14 @@ async function forkAgentImpl(parent, options, deps) {
1616
1843
  return {
1617
1844
  result: result.result,
1618
1845
  toolCalls: [],
1619
- usage: extractUsage(result)
1846
+ usage: extractUsage2(result)
1620
1847
  };
1621
1848
  });
1622
1849
  } finally {
1623
1850
  await fork.dispose();
1624
1851
  }
1625
1852
  }
1626
- function extractUsage(result) {
1853
+ function extractUsage2(result) {
1627
1854
  if (typeof result !== "object" || result === null) {
1628
1855
  return { inputTokens: 0, outputTokens: 0 };
1629
1856
  }
@@ -2059,342 +2286,115 @@ async function runWorkAndFinalize(taskId, aborter, work) {
2059
2286
  type: "progress",
2060
2287
  taskId,
2061
2288
  at: Date.now(),
2062
- payload
2063
- });
2064
- }
2065
- };
2066
- try {
2067
- const result = await reentryAls.run(true, () => Promise.resolve().then(() => work(ctx)));
2068
- if (aborter.signal.aborted) {
2069
- const cancelledAt = Date.now();
2070
- await transition(taskId, "cancelled", { cancelledAt });
2071
- emitToSubscribers(taskId, { type: "cancelled", taskId, cancelledAt });
2072
- return;
2073
- }
2074
- const finishedAt = Date.now();
2075
- await transition(taskId, "finished", { finishedAt, result });
2076
- emitToSubscribers(taskId, { type: "finished", taskId, finishedAt, result });
2077
- } catch (err) {
2078
- if (aborter.signal.aborted) {
2079
- const cancelledAt = Date.now();
2080
- await transition(taskId, "cancelled", { cancelledAt });
2081
- emitToSubscribers(taskId, { type: "cancelled", taskId, cancelledAt });
2082
- return;
2083
- }
2084
- const erroredAt = Date.now();
2085
- const error = err instanceof Error ? { code: err.code ?? "work_threw", message: err.message } : { code: "work_threw", message: String(err) };
2086
- await transition(taskId, "error", { erroredAt, error });
2087
- emitToSubscribers(taskId, { type: "errored", taskId, erroredAt, error });
2088
- }
2089
- }
2090
- async function checkCancelRequestedAt(taskId, aborter) {
2091
- if (aborter.signal.aborted) return;
2092
- try {
2093
- const handle = await state.store.get(taskId);
2094
- if (handle?.cancelRequested === true) {
2095
- aborter.abort("cancelRequested");
2096
- }
2097
- } catch {
2098
- }
2099
- }
2100
- async function acquireSlot() {
2101
- if (reentryAls.getStore() === true) {
2102
- return () => {
2103
- };
2104
- }
2105
- return state.semaphore.acquire();
2106
- }
2107
- async function submit(internal) {
2108
- state.firstSubmitSeen = true;
2109
- startEvictTimerIfNeeded();
2110
- const resolvedId = resolveIdInternal(internal);
2111
- const submitSpan = startTaskSubmitSpan({ taskId: resolvedId, kind: internal.kind });
2112
- const existing = await state.store.get(resolvedId);
2113
- if (existing !== void 0) {
2114
- submitSpan.end();
2115
- return existing;
2116
- }
2117
- const queuedHandle = await buildAndInsertQueued(internal, resolvedId);
2118
- submitSpan.end();
2119
- if (internal.signal?.aborted === true) {
2120
- return shortCircuitAborted(queuedHandle, internal.signal);
2121
- }
2122
- const aborter = new AbortController();
2123
- state.aborters.set(resolvedId, aborter);
2124
- if (internal.signal !== void 0) {
2125
- internal.signal.addEventListener("abort", () => aborter.abort(internal.signal?.reason), {
2126
- once: true
2127
- });
2128
- }
2129
- const release = await acquireSlot();
2130
- void (async () => {
2131
- try {
2132
- await checkCancelRequestedAt(resolvedId, aborter);
2133
- if (aborter.signal.aborted) {
2134
- const cancelledAt = Date.now();
2135
- await transition(resolvedId, "cancelled", { cancelledAt });
2136
- emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
2137
- return;
2138
- }
2139
- const startedAt = Date.now();
2140
- await transition(resolvedId, "running", { startedAt });
2141
- emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
2142
- await runWorkAndFinalize(resolvedId, aborter, internal.work);
2143
- } finally {
2144
- release();
2145
- state.aborters.delete(resolvedId);
2146
- }
2147
- })();
2148
- return queuedHandle;
2149
- }
2150
- async function get(id) {
2151
- if (!isValidTaskId(id, true)) return void 0;
2152
- return state.store.get(id);
2153
- }
2154
- var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state;
2155
- var init_registry = __esm({
2156
- "src/internal/task/registry.ts"() {
2157
- init_errors();
2158
- init_task();
2159
- init_async_semaphore();
2160
- init_ring_buffer();
2161
- init_store();
2162
- init_subscribe();
2163
- init_telemetry();
2164
- DEFAULT_CONCURRENCY = 8;
2165
- DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
2166
- EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
2167
- RING_CAP = 64;
2168
- reentryAls = new async_hooks.AsyncLocalStorage();
2169
- state = buildState({});
2170
- }
2171
- });
2172
- function toJsonSchema(schema, options = { unrepresentable: "any" }) {
2173
- return zod.toJSONSchema(schema, options);
2174
- }
2175
- var init_to_json_schema = __esm({
2176
- "src/internal/zod/to-json-schema.ts"() {
2177
- }
2178
- });
2179
- function requireZod() {
2180
- if (cachedZ !== void 0) return cachedZ;
2181
- const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('eval.cjs', document.baseURI).href)));
2182
- let mod;
2183
- try {
2184
- mod = r("zod");
2185
- } catch (cause) {
2186
- throw new ConfigurationError(
2187
- 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
2188
- { code: "zod_not_installed", cause }
2189
- );
2190
- }
2191
- cachedZ = mod.z ?? mod;
2192
- return cachedZ;
2193
- }
2194
- function makeOutputTool(jsonSchema, onCapture) {
2195
- return {
2196
- name: "output",
2197
- description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
2198
- inputSchema: jsonSchema,
2199
- handler: (input) => {
2200
- const out = onCapture(input);
2201
- if (typeof out === "string") return out;
2202
- if (out instanceof Promise) return out;
2203
- return "";
2204
- }
2205
- };
2206
- }
2207
- function buildTransientAgentOptions(params) {
2208
- return {
2209
- model: params.model,
2210
- local: params.local,
2211
- tools: [params.outputTool],
2212
- systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
2213
- ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
2214
- ...params.providers !== void 0 ? { providers: params.providers } : {}
2215
- };
2216
- }
2217
- function extractUsage2(result) {
2218
- const u = result.usage;
2219
- if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
2220
- return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
2221
- }
2222
- function buildToolPrompt(prompt) {
2223
- return `${prompt}
2224
-
2225
- Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
2226
- }
2227
- function setupStructuredOutput(schema, maxRetries) {
2228
- const z7 = requireZod();
2229
- const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
2230
- return {
2231
- z: z7,
2232
- jsonSchema,
2233
- maxRetries: maxRetries ?? 1,
2234
- initialUsage: { inputTokens: 0, outputTokens: 0 }
2235
- };
2236
- }
2237
- async function disposeAndDeleteTransient(agent, deletor) {
2238
- await agent.dispose();
2239
- try {
2240
- await deletor(agent.agentId);
2241
- } catch {
2242
- }
2243
- }
2244
- var cachedZ;
2245
- var init_structured_output_helpers = __esm({
2246
- "src/internal/structured-output-helpers.ts"() {
2247
- init_errors();
2248
- init_to_json_schema();
2249
- }
2250
- });
2251
-
2252
- // src/generate-object.ts
2253
- var generate_object_exports = {};
2254
- __export(generate_object_exports, {
2255
- GenerateObjectError: () => GenerateObjectError,
2256
- generateObjectImpl: () => generateObjectImpl
2257
- });
2258
- function salvagePartial(schema, raw) {
2259
- if (typeof raw !== "object" || raw === null) return raw;
2260
- const shape = schema.shape;
2261
- if (shape === void 0 || typeof shape !== "object") return raw;
2262
- const rawObj = raw;
2263
- const out = {};
2264
- for (const [key, fieldSchema] of Object.entries(shape)) {
2265
- if (typeof fieldSchema?.safeParse !== "function") continue;
2266
- const parsed = fieldSchema.safeParse(rawObj[key]);
2267
- if (parsed.success) out[key] = parsed.data;
2268
- }
2269
- return out;
2270
- }
2271
- async function runReasoningPhase(options, deps) {
2272
- const reasoningOptions = {
2273
- model: options.model,
2274
- local: options.local,
2275
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
2276
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
2277
- ...options.providers !== void 0 ? { providers: options.providers } : {}
2278
- };
2279
- const reasoningAgent = await deps.create(reasoningOptions);
2280
- try {
2281
- const run = await reasoningAgent.send(options.prompt);
2282
- const result = await run.wait();
2283
- const text = result.result;
2284
- return typeof text === "string" ? text : options.prompt;
2285
- } finally {
2286
- await disposeAndDeleteTransient(reasoningAgent, deps.delete);
2287
- }
2288
- }
2289
- async function generateObjectImpl(options, deps) {
2290
- const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
2291
- options.schema,
2292
- options.maxRetries
2293
- );
2294
- let capturedRaw;
2295
- let lastUsage = initialUsage;
2296
- const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
2297
- class CaptureSentinel extends Error {
2298
- constructor(captured) {
2299
- super("generate-object-capture");
2300
- this.captured = captured;
2301
- }
2302
- captured;
2303
- [sentinel] = true;
2304
- }
2305
- const outputTool = makeOutputTool(jsonSchema, (input) => {
2306
- if (capturedRaw === void 0) {
2307
- capturedRaw = input;
2308
- }
2309
- throw new CaptureSentinel(input);
2310
- });
2311
- const reasoningText = options.structuringModel !== void 0 ? await runReasoningPhase(options, deps) : void 0;
2312
- const structuringModel = options.structuringModel ?? options.model;
2313
- const structuringPrompt = reasoningText ?? options.prompt;
2314
- const agentOptions = buildTransientAgentOptions({
2315
- model: structuringModel,
2316
- local: options.local,
2317
- outputTool,
2318
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
2319
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
2320
- ...options.providers !== void 0 ? { providers: options.providers } : {}
2321
- });
2322
- const agent = await deps.create(agentOptions);
2289
+ payload
2290
+ });
2291
+ }
2292
+ };
2323
2293
  try {
2324
- const userMessage = buildToolPrompt(structuringPrompt);
2325
- let lastParseError;
2326
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
2327
- capturedRaw = void 0;
2328
- const run = await agent.send(userMessage);
2329
- const result = await run.wait();
2330
- lastUsage = extractUsage2(result);
2331
- if (capturedRaw === void 0) {
2332
- if (result.status === "error" && result.error !== void 0) {
2333
- throw new GenerateObjectError(
2334
- "no_tool_call",
2335
- `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
2336
- result.error
2337
- );
2338
- }
2339
- if (attempt === maxRetries) {
2340
- throw new GenerateObjectError(
2341
- "no_tool_call",
2342
- "The model returned text instead of calling the `output` tool."
2343
- );
2344
- }
2345
- continue;
2346
- }
2347
- const parsed = options.schema.safeParse(capturedRaw);
2348
- if (parsed.success) {
2349
- return {
2350
- object: parsed.data,
2351
- raw: capturedRaw,
2352
- usage: lastUsage,
2353
- finishReason: "tool_use"
2354
- };
2355
- }
2356
- lastParseError = parsed.error;
2294
+ const result = await reentryAls.run(true, () => Promise.resolve().then(() => work(ctx)));
2295
+ if (aborter.signal.aborted) {
2296
+ const cancelledAt = Date.now();
2297
+ await transition(taskId, "cancelled", { cancelledAt });
2298
+ emitToSubscribers(taskId, { type: "cancelled", taskId, cancelledAt });
2299
+ return;
2357
2300
  }
2358
- if (options.errorStrategy === "return-raw") {
2359
- return {
2360
- object: capturedRaw,
2361
- raw: capturedRaw,
2362
- usage: lastUsage,
2363
- finishReason: "tool_use"
2364
- };
2301
+ const finishedAt = Date.now();
2302
+ await transition(taskId, "finished", { finishedAt, result });
2303
+ emitToSubscribers(taskId, { type: "finished", taskId, finishedAt, result });
2304
+ } catch (err) {
2305
+ if (aborter.signal.aborted) {
2306
+ const cancelledAt = Date.now();
2307
+ await transition(taskId, "cancelled", { cancelledAt });
2308
+ emitToSubscribers(taskId, { type: "cancelled", taskId, cancelledAt });
2309
+ return;
2365
2310
  }
2366
- if (options.errorStrategy === "return-partial") {
2367
- return {
2368
- object: salvagePartial(options.schema, capturedRaw),
2369
- raw: capturedRaw,
2370
- usage: lastUsage,
2371
- finishReason: "tool_use"
2372
- };
2311
+ const erroredAt = Date.now();
2312
+ const error = err instanceof Error ? { code: err.code ?? "work_threw", message: err.message } : { code: "work_threw", message: String(err) };
2313
+ await transition(taskId, "error", { erroredAt, error });
2314
+ emitToSubscribers(taskId, { type: "errored", taskId, erroredAt, error });
2315
+ }
2316
+ }
2317
+ async function checkCancelRequestedAt(taskId, aborter) {
2318
+ if (aborter.signal.aborted) return;
2319
+ try {
2320
+ const handle = await state.store.get(taskId);
2321
+ if (handle?.cancelRequested === true) {
2322
+ aborter.abort("cancelRequested");
2373
2323
  }
2374
- throw new GenerateObjectError(
2375
- "parse_failed",
2376
- "Schema parse failed after all retries.",
2377
- lastParseError
2378
- );
2379
- } finally {
2380
- await disposeAndDeleteTransient(agent, deps.delete);
2324
+ } catch {
2381
2325
  }
2382
2326
  }
2383
- var GenerateObjectError;
2384
- var init_generate_object = __esm({
2385
- "src/generate-object.ts"() {
2386
- init_structured_output_helpers();
2387
- GenerateObjectError = class extends Error {
2388
- name = "GenerateObjectError";
2389
- code;
2390
- cause;
2391
- constructor(code, message, cause) {
2392
- super(message);
2393
- this.code = code;
2394
- if (cause !== void 0) this.cause = cause;
2395
- }
2327
+ async function acquireSlot() {
2328
+ if (reentryAls.getStore() === true) {
2329
+ return () => {
2396
2330
  };
2397
2331
  }
2332
+ return state.semaphore.acquire();
2333
+ }
2334
+ async function submit(internal) {
2335
+ state.firstSubmitSeen = true;
2336
+ startEvictTimerIfNeeded();
2337
+ const resolvedId = resolveIdInternal(internal);
2338
+ const submitSpan = startTaskSubmitSpan({ taskId: resolvedId, kind: internal.kind });
2339
+ const existing = await state.store.get(resolvedId);
2340
+ if (existing !== void 0) {
2341
+ submitSpan.end();
2342
+ return existing;
2343
+ }
2344
+ const queuedHandle = await buildAndInsertQueued(internal, resolvedId);
2345
+ submitSpan.end();
2346
+ if (internal.signal?.aborted === true) {
2347
+ return shortCircuitAborted(queuedHandle, internal.signal);
2348
+ }
2349
+ const aborter = new AbortController();
2350
+ state.aborters.set(resolvedId, aborter);
2351
+ if (internal.signal !== void 0) {
2352
+ internal.signal.addEventListener("abort", () => aborter.abort(internal.signal?.reason), {
2353
+ once: true
2354
+ });
2355
+ }
2356
+ const release = await acquireSlot();
2357
+ void (async () => {
2358
+ try {
2359
+ await checkCancelRequestedAt(resolvedId, aborter);
2360
+ if (aborter.signal.aborted) {
2361
+ const cancelledAt = Date.now();
2362
+ await transition(resolvedId, "cancelled", { cancelledAt });
2363
+ emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
2364
+ return;
2365
+ }
2366
+ const startedAt = Date.now();
2367
+ await transition(resolvedId, "running", { startedAt });
2368
+ emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
2369
+ await runWorkAndFinalize(resolvedId, aborter, internal.work);
2370
+ } finally {
2371
+ release();
2372
+ state.aborters.delete(resolvedId);
2373
+ }
2374
+ })();
2375
+ return queuedHandle;
2376
+ }
2377
+ async function get(id) {
2378
+ if (!isValidTaskId(id, true)) return void 0;
2379
+ return state.store.get(id);
2380
+ }
2381
+ var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state;
2382
+ var init_registry = __esm({
2383
+ "src/internal/task/registry.ts"() {
2384
+ init_errors();
2385
+ init_task();
2386
+ init_async_semaphore();
2387
+ init_ring_buffer();
2388
+ init_store();
2389
+ init_subscribe();
2390
+ init_telemetry();
2391
+ DEFAULT_CONCURRENCY = 8;
2392
+ DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
2393
+ EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
2394
+ RING_CAP = 64;
2395
+ reentryAls = new async_hooks.AsyncLocalStorage();
2396
+ state = buildState({});
2397
+ }
2398
2398
  });
2399
2399
 
2400
2400
  // src/stream-object.ts
@@ -2451,7 +2451,7 @@ async function* streamObjectImpl(options, deps) {
2451
2451
  }
2452
2452
  }
2453
2453
  const result = await run.wait();
2454
- lastUsage = extractUsage2(result);
2454
+ lastUsage = extractUsage(result);
2455
2455
  if (capturedRaw === void 0) {
2456
2456
  if (result.status === "error" && result.error !== void 0) {
2457
2457
  throw new StreamObjectError(
@@ -2797,6 +2797,7 @@ var AgentBuilder = class {
2797
2797
  constructor(deps) {
2798
2798
  this.deps = deps;
2799
2799
  }
2800
+ /** SE8 — accepts a bare-string id shorthand (`"openai/gpt-4o-mini"`) or a {@link ModelSelection}. */
2800
2801
  model(m) {
2801
2802
  this.opts.model = m;
2802
2803
  return this;
@@ -3146,6 +3147,69 @@ function isLocalAgentId(id) {
3146
3147
  return id.startsWith(PREFIX.localAgent);
3147
3148
  }
3148
3149
 
3150
+ // src/internal/runtime/config/default-model.ts
3151
+ var DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
3152
+
3153
+ // src/agent-generate.ts
3154
+ async function agentGenerate(agent, agentModel, agentApiKey, agentLocal, input, options) {
3155
+ const { output, maxRetries, errorStrategy, ...sendOptions } = options;
3156
+ const run = await agent.send(input, sendOptions);
3157
+ const result = await run.wait();
3158
+ const { generateObjectImpl: generateObjectImpl2, GenerateObjectError: GenerateObjectError2 } = await Promise.resolve().then(() => (init_generate_object(), generate_object_exports));
3159
+ const answer = structurableAnswerOrThrow(result, GenerateObjectError2);
3160
+ const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
3161
+ const facade = getAgentFacade2();
3162
+ const structured = await generateObjectImpl2(
3163
+ {
3164
+ prompt: answer,
3165
+ schema: output,
3166
+ // `agentModel` arrives already normalized (`this.model` passed through
3167
+ // `normalizeModel` in the LocalAgent/CloudAgent constructor), so the widened
3168
+ // `string | ModelSelection` field only ever receives a `ModelSelection` here.
3169
+ model: agentModel ?? { id: DEFAULT_AGENTIC_MODEL_ID },
3170
+ // `local` is required to keep the transient structuring agent local-only;
3171
+ // default to the process cwd when the agent had no explicit local config.
3172
+ local: agentLocal ?? { cwd: process.cwd() },
3173
+ ...agentApiKey !== void 0 ? { apiKey: agentApiKey } : {},
3174
+ ...maxRetries !== void 0 ? { maxRetries } : {},
3175
+ ...errorStrategy !== void 0 ? { errorStrategy } : {}
3176
+ },
3177
+ {
3178
+ create: (opts) => facade.create(opts),
3179
+ delete: (agentId) => facade.delete(agentId)
3180
+ }
3181
+ );
3182
+ return {
3183
+ object: structured.object,
3184
+ result,
3185
+ raw: structured.raw,
3186
+ usage: structured.usage
3187
+ };
3188
+ }
3189
+ function structurableAnswerOrThrow(result, GenerateObjectError2) {
3190
+ if (result.status === "error") {
3191
+ throw new GenerateObjectError2(
3192
+ "no_tool_call",
3193
+ `Agent run failed before an answer could be structured: ${result.error?.message ?? "unknown error"} [${result.error?.code ?? "?"}]`,
3194
+ result.error
3195
+ );
3196
+ }
3197
+ if (result.status === "cancelled") {
3198
+ throw new GenerateObjectError2(
3199
+ "no_tool_call",
3200
+ "Agent run was cancelled before an answer could be structured."
3201
+ );
3202
+ }
3203
+ const answer = result.result;
3204
+ if (answer === void 0 || answer.length === 0) {
3205
+ throw new GenerateObjectError2(
3206
+ "no_tool_call",
3207
+ "The tool loop finished with no text answer (tool-only completion) \u2014 there is nothing to structure."
3208
+ );
3209
+ }
3210
+ return answer;
3211
+ }
3212
+
3149
3213
  // src/internal/runtime/cloud/cloud-agent.ts
3150
3214
  init_errors();
3151
3215
  init_cwd_mutex();
@@ -3296,8 +3360,19 @@ function safeFilenameForId(id, options) {
3296
3360
  return `h-${crypto.createHash("sha256").update(id).digest("hex").slice(0, 16)}`;
3297
3361
  }
3298
3362
 
3299
- // src/internal/runtime/config/default-model.ts
3300
- var DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
3363
+ // src/internal/runtime/model-selection.ts
3364
+ init_errors();
3365
+ function normalizeModel(m) {
3366
+ if (m === void 0 || typeof m !== "string") return m;
3367
+ const id = m.trim();
3368
+ if (id.length === 0) {
3369
+ throw new ConfigurationError(
3370
+ 'model must be a non-empty "provider/model" id string or a ModelSelection object',
3371
+ { code: "invalid_model_selection" }
3372
+ );
3373
+ }
3374
+ return { id };
3375
+ }
3301
3376
 
3302
3377
  // src/internal/runtime/registry/agent-registry-store.ts
3303
3378
  init_cwd_mutex();
@@ -3374,7 +3449,10 @@ var REGISTRY_RELATIVE_PATH = path.join(".theokit", "agents", "registry.json");
3374
3449
  function stripSecretsFromOptions(options) {
3375
3450
  return assignDefined({
3376
3451
  name: options.name,
3377
- model: options.model !== void 0 ? { id: options.model.id } : void 0,
3452
+ model: (() => {
3453
+ const m = normalizeModel(options.model);
3454
+ return m !== void 0 ? { id: m.id } : void 0;
3455
+ })(),
3378
3456
  systemPrompt: typeof options.systemPrompt === "string" ? options.systemPrompt : void 0,
3379
3457
  local: serializeLocal(options.local),
3380
3458
  cloud: serializeCloud(options.cloud),
@@ -3659,7 +3737,8 @@ function serializeCloudAgentConfig(options) {
3659
3737
  cloud: serializeCloud2(options.cloud)
3660
3738
  };
3661
3739
  if (typeof options.agentId === "string") payload.agentId = options.agentId;
3662
- if (options.model !== void 0) payload.model = { id: options.model.id };
3740
+ const cfgModel = normalizeModel(options.model);
3741
+ if (cfgModel !== void 0) payload.model = { id: cfgModel.id };
3663
3742
  if (typeof options.systemPrompt === "string") payload.systemPrompt = options.systemPrompt;
3664
3743
  const skills = serializeSkills(options.skills);
3665
3744
  if (skills !== void 0) payload.skills = skills;
@@ -4555,6 +4634,7 @@ function applyScriptMetrics(base, script) {
4555
4634
  if (script.cost !== void 0) base.cost = script.cost;
4556
4635
  if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
4557
4636
  if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
4637
+ if (script.origin !== void 0) base.origin = script.origin;
4558
4638
  }
4559
4639
 
4560
4640
  // src/internal/runtime/cloud/cloud-run.ts
@@ -4910,7 +4990,7 @@ var CloudAgent = class {
4910
4990
  disposed = false;
4911
4991
  constructor(options, providedAgentId) {
4912
4992
  this.agentId = providedAgentId ?? options.agentId ?? generateCloudAgentId();
4913
- this.model = options.model;
4993
+ this.model = normalizeModel(options.model);
4914
4994
  this.options = options;
4915
4995
  this.cloudPayload = serializeCloudAgentConfig({ ...options, agentId: this.agentId });
4916
4996
  const repoUrls = (options.cloud?.repos ?? []).map((repo) => repo.url);
@@ -4940,6 +5020,17 @@ var CloudAgent = class {
4940
5020
  const apiKey = resolveApiKey(this.options.apiKey);
4941
5021
  return isFixtureApiKey(apiKey) && getConfiguredBaseUrl() === void 0;
4942
5022
  }
5023
+ // SE9 — integrated structured output; delegates to the shared helper.
5024
+ generate(message, options) {
5025
+ return agentGenerate(
5026
+ this,
5027
+ this.model,
5028
+ this.options.apiKey,
5029
+ this.options.local,
5030
+ message,
5031
+ options
5032
+ );
5033
+ }
4943
5034
  async send(message, options = {}) {
4944
5035
  if (options.tools !== void 0 && options.tools.length > 0) {
4945
5036
  throw new ConfigurationError(
@@ -4970,7 +5061,7 @@ var CloudAgent = class {
4970
5061
  });
4971
5062
  }
4972
5063
  async sendLocked(message, options) {
4973
- const overrideModel = options.model;
5064
+ const overrideModel = normalizeModel(options.model);
4974
5065
  if (overrideModel !== void 0) {
4975
5066
  this.model = overrideModel;
4976
5067
  updateRegisteredAgent(this.agentId, { model: overrideModel });
@@ -5884,18 +5975,18 @@ var ALL_ADAPTERS = [
5884
5975
  arizeAdapter,
5885
5976
  braintrustAdapter
5886
5977
  ];
5887
- var registered = /* @__PURE__ */ new Set();
5978
+ var registered2 = /* @__PURE__ */ new Set();
5888
5979
  function tryAutoRegisterAdapters(settings) {
5889
5980
  if (settings?.enabled !== true) return;
5890
5981
  if (settings.autoDetect === false) return;
5891
5982
  const disabled = new Set(settings.disable ?? []);
5892
5983
  for (const adapter of ALL_ADAPTERS) {
5893
- if (registered.has(adapter.moduleName)) continue;
5984
+ if (registered2.has(adapter.moduleName)) continue;
5894
5985
  if (disabled.has(adapter.displayName.toLowerCase())) continue;
5895
5986
  if (!adapter.detect()) continue;
5896
5987
  try {
5897
5988
  adapter.register();
5898
- registered.add(adapter.moduleName);
5989
+ registered2.add(adapter.moduleName);
5899
5990
  process.stderr.write(`[theokit-sdk] telemetry: ${adapter.displayName} auto-instrumented.
5900
5991
  `);
5901
5992
  } catch (cause) {
@@ -6458,6 +6549,26 @@ function paginate(items, opts) {
6458
6549
  return items.slice(start, end);
6459
6550
  }
6460
6551
 
6552
+ // src/internal/persistence/session-meta.ts
6553
+ function applyMetaPatch(current, patch) {
6554
+ const next = {};
6555
+ if (current.title !== void 0) next.title = current.title;
6556
+ if (current.tag !== void 0) next.tag = current.tag;
6557
+ if (patch.title === null) delete next.title;
6558
+ else if (patch.title !== void 0) next.title = patch.title;
6559
+ if (patch.tag === null) delete next.tag;
6560
+ else if (patch.tag !== void 0) next.tag = patch.tag;
6561
+ return next;
6562
+ }
6563
+ function coerceSessionMeta(raw) {
6564
+ if (typeof raw !== "object" || raw === null) return void 0;
6565
+ const obj = raw;
6566
+ const meta = {};
6567
+ if (typeof obj.title === "string") meta.title = obj.title;
6568
+ if (typeof obj.tag === "string") meta.tag = obj.tag;
6569
+ return meta.title === void 0 && meta.tag === void 0 ? void 0 : meta;
6570
+ }
6571
+
6461
6572
  // src/internal/persistence/conversation-storage-fs.ts
6462
6573
  var FileSystemConversationStorage = class {
6463
6574
  #root;
@@ -6508,6 +6619,37 @@ var FileSystemConversationStorage = class {
6508
6619
  async compact(conversationId, maxTurns) {
6509
6620
  await compactSessionFile(this.#root, conversationId, maxTurns);
6510
6621
  }
6622
+ // SE4 — session metadata persisted as a per-conversation sidecar
6623
+ // `<root>/.theokit/agents/<safeId>/session.json` (same sanitized perimeter as
6624
+ // the transcript). Kept separate from messages.jsonl so a title/tag write does
6625
+ // not rewrite the append-only log.
6626
+ #metaPath(conversationId) {
6627
+ const safe3 = sanitizeIdentifier(conversationId, { maxLen: 128 });
6628
+ return safePathJoin(this.#root, ".theokit", "agents", safe3, "session.json");
6629
+ }
6630
+ async getSessionMeta(conversationId) {
6631
+ try {
6632
+ const raw = await promises.readFile(this.#metaPath(conversationId), "utf8");
6633
+ return coerceSessionMeta(JSON.parse(raw));
6634
+ } catch (cause) {
6635
+ if (cause.code === "ENOENT") return void 0;
6636
+ throw cause;
6637
+ }
6638
+ }
6639
+ async setSessionMeta(conversationId, patch) {
6640
+ const metaPath = this.#metaPath(conversationId);
6641
+ await promises.mkdir(path.dirname(metaPath), { recursive: true });
6642
+ await withFileLock(metaPath, async () => {
6643
+ let current = {};
6644
+ try {
6645
+ current = coerceSessionMeta(JSON.parse(await promises.readFile(metaPath, "utf8"))) ?? {};
6646
+ } catch (cause) {
6647
+ if (cause.code !== "ENOENT") throw cause;
6648
+ }
6649
+ const next = applyMetaPatch(current, patch);
6650
+ await promises.writeFile(metaPath, redactSecrets(JSON.stringify(next)), "utf8");
6651
+ });
6652
+ }
6511
6653
  async dispose() {
6512
6654
  }
6513
6655
  };
@@ -8427,7 +8569,7 @@ function bootstrapSubmanagers(args) {
8427
8569
  const providerCount = (args.options.providers?.routes?.length ?? 0) + enabledPluginNames(args.options.plugins).length;
8428
8570
  if (providerCount > 0 || args.options.providers !== void 0) {
8429
8571
  out.providers = new ProvidersManagerImpl(
8430
- args.options.model,
8572
+ normalizeModel(args.options.model),
8431
8573
  args.options.providers,
8432
8574
  args.options.plugins
8433
8575
  );
@@ -8497,6 +8639,7 @@ function createLocalRun(options) {
8497
8639
  projectMcpServers: options.projectMcpServers,
8498
8640
  ...options.persistMemoryFact !== void 0 ? { persistMemoryFact: options.persistMemoryFact } : {}
8499
8641
  });
8642
+ if (options.sendOptions.origin !== void 0) script.origin = options.sendOptions.origin;
8500
8643
  const handle = new LocalRun({
8501
8644
  id,
8502
8645
  agentId: options.agentId,
@@ -9145,6 +9288,15 @@ async function emitReasoningDeltaCallback(inputs, text) {
9145
9288
  );
9146
9289
  }
9147
9290
 
9291
+ // src/types/run-events.ts
9292
+ function emitRunEvent(sink, event) {
9293
+ if (sink === void 0) return;
9294
+ try {
9295
+ sink(event);
9296
+ } catch {
9297
+ }
9298
+ }
9299
+
9148
9300
  // src/internal/agent-loop/tool-dispatch.ts
9149
9301
  init_async_local_storage();
9150
9302
 
@@ -9242,6 +9394,22 @@ function coerceArgsToSchema(args, schema) {
9242
9394
  return { value: out, changed };
9243
9395
  }
9244
9396
 
9397
+ // src/tool-error.ts
9398
+ init_errors();
9399
+ var ToolError = class extends TheokitAgentError {
9400
+ name = "ToolError";
9401
+ /** The error content surfaced to the model: a string, or text/image blocks. */
9402
+ content;
9403
+ constructor(content, options = {}) {
9404
+ super(renderToolErrorMessage(content), { ...options, isRetryable: false });
9405
+ this.content = content;
9406
+ }
9407
+ };
9408
+ function renderToolErrorMessage(content) {
9409
+ if (typeof content === "string") return content;
9410
+ return content.map((block) => block.type === "text" ? block.text : `[${block.source.media_type} image]`).join("\n");
9411
+ }
9412
+
9245
9413
  // src/internal/runtime/tools/shell-tool.ts
9246
9414
  async function runShell(options) {
9247
9415
  if (options.sandbox === true && isObviouslyUnsafe(options.command)) {
@@ -9281,23 +9449,27 @@ async function executeTool(inputs, resolved, call) {
9281
9449
  if (resolved.origin === "shell") return runShellTool(inputs, call);
9282
9450
  if (resolved.origin === "memory") return runMemoryTool(resolved, call, inputs.context);
9283
9451
  if (resolved.origin === "custom")
9284
- return runCustomTool(resolved, call, inputs.signal, inputs.context);
9452
+ return runCustomTool(resolved, call, inputs.signal, inputs.context, inputs.messages);
9285
9453
  return runMcpTool(inputs, resolved, call);
9286
9454
  }
9287
9455
  async function runMemoryTool(resolved, call, context) {
9288
9456
  return runHandlerTool("memory", resolved.memoryHandler, call, void 0, context);
9289
9457
  }
9290
- async function runCustomTool(resolved, call, signal, context) {
9291
- return runHandlerTool("custom", resolved.customHandler, call, signal, context);
9458
+ async function runCustomTool(resolved, call, signal, context, messages) {
9459
+ return runHandlerTool("custom", resolved.customHandler, call, signal, context, messages);
9292
9460
  }
9293
- async function runHandlerTool(kind, handler, call, signal, context) {
9461
+ async function runHandlerTool(kind, handler, call, signal, context, messages) {
9294
9462
  if (handler === void 0) {
9295
9463
  return { stdout: "", stderr: `${kind} tool ${call.name} has no handler`, exitCode: 127 };
9296
9464
  }
9297
9465
  try {
9298
- const stdout = await handler(call.input, { signal, context });
9299
- return { stdout, stderr: "", exitCode: 0 };
9466
+ const out = await handler(call.input, { signal, context, messages });
9467
+ if (typeof out !== "string") return { stdout: "", stderr: "", exitCode: 0, content: out };
9468
+ return { stdout: out, stderr: "", exitCode: 0 };
9300
9469
  } catch (cause) {
9470
+ if (cause instanceof ToolError) {
9471
+ return { stdout: "", stderr: cause.message, exitCode: 1, content: cause.content };
9472
+ }
9301
9473
  const message = cause instanceof Error ? cause.message : String(cause);
9302
9474
  return { stdout: "", stderr: message, exitCode: 1 };
9303
9475
  }
@@ -9416,6 +9588,11 @@ async function dispatchSingleCall(inputs, tools, call, events, parentSpan) {
9416
9588
  toolSpan?.end();
9417
9589
  return fileVeto;
9418
9590
  }
9591
+ emitRunEvent(inputs.runEventSink, {
9592
+ type: "tool_progress",
9593
+ toolName: workingCall.name,
9594
+ toolCallId: callId
9595
+ });
9419
9596
  const result = await runToolWithLifecycle(inputs, resolved, workingCall, callId);
9420
9597
  await inputs.pluginManager?.runPostToolCallHooks({
9421
9598
  name: workingCall.name,
@@ -9442,6 +9619,13 @@ function applyRepairAndExtractCall(tools, call) {
9442
9619
  function vetoFromForkWhitelist(inputs, call, callId, events) {
9443
9620
  const whitelistDecision = checkToolWhitelist(call.name);
9444
9621
  if (whitelistDecision.allowed) return void 0;
9622
+ emitRunEvent(inputs.runEventSink, {
9623
+ type: "permission_denied",
9624
+ toolName: call.name,
9625
+ toolCallId: callId,
9626
+ source: "fork_whitelist",
9627
+ message: whitelistDecision.reason ?? "tool not available in fork"
9628
+ });
9445
9629
  events.push(buildToolUseRunning(inputs, callId, call));
9446
9630
  events.push(
9447
9631
  buildToolUseCompleted(inputs, callId, call, {
@@ -9478,6 +9662,13 @@ async function vetoFromPluginPreHook(inputs, call, callId, events) {
9478
9662
  runId: inputs.runId
9479
9663
  });
9480
9664
  if (pluginVeto === void 0) return void 0;
9665
+ emitRunEvent(inputs.runEventSink, {
9666
+ type: "permission_denied",
9667
+ toolName: call.name,
9668
+ toolCallId: callId,
9669
+ source: "plugin",
9670
+ message: pluginVeto.message
9671
+ });
9481
9672
  events.push(
9482
9673
  buildToolUseCompleted(inputs, callId, call, {
9483
9674
  stdout: "",
@@ -9500,6 +9691,13 @@ async function vetoFromFileHookPreDecision(inputs, call, callId, events) {
9500
9691
  runId: inputs.runId
9501
9692
  });
9502
9693
  if (!preDecision.blocked) return void 0;
9694
+ emitRunEvent(inputs.runEventSink, {
9695
+ type: "permission_denied",
9696
+ toolName: call.name,
9697
+ toolCallId: callId,
9698
+ source: "file_hook",
9699
+ message: preDecision.reason ?? "blocked by hook"
9700
+ });
9503
9701
  events.push(
9504
9702
  buildToolUseCompleted(inputs, callId, call, {
9505
9703
  stdout: "",
@@ -9543,7 +9741,9 @@ async function runToolWithLifecycle(inputs, resolved, call, callId) {
9543
9741
  await safeEmitToolHook(inputs.onToolEnd, {
9544
9742
  toolName: call.name,
9545
9743
  args: call.input,
9546
- result: result.stdout,
9744
+ // SE7 — a block-returning handler has empty `stdout`; surface its structured
9745
+ // content to the hook instead of an empty string.
9746
+ result: result.content !== void 0 ? result.content : result.stdout,
9547
9747
  conversationId: inputs.agentId,
9548
9748
  callId,
9549
9749
  durationMs
@@ -9565,7 +9765,10 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
9565
9765
  output: {
9566
9766
  stdout: result.stdout,
9567
9767
  stderr: result.stderr,
9568
- exitCode: result.exitCode ?? 0
9768
+ exitCode: result.exitCode ?? 0,
9769
+ // SE7 — structured content (text + image blocks) when the handler
9770
+ // returned/threw blocks; absent for the string path.
9771
+ ...result.content !== void 0 ? { content: result.content } : {}
9569
9772
  },
9570
9773
  agentId: inputs.agentId,
9571
9774
  runId: inputs.runId
@@ -9578,7 +9781,9 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
9578
9781
  return {
9579
9782
  type: "tool_result",
9580
9783
  toolUseId: call.id,
9581
- content: renderToolResult(result),
9784
+ // SE7 — structured content blocks (handler-returned or ToolError-carried)
9785
+ // are authoritative; otherwise the legacy string rendering.
9786
+ content: result.content !== void 0 ? result.content : renderToolResult(result),
9582
9787
  ...result.exitCode !== 0 && result.exitCode !== void 0 ? { isError: true } : {}
9583
9788
  };
9584
9789
  }
@@ -9627,6 +9832,29 @@ function buildToolUseCompleted(inputs, callId, call, result) {
9627
9832
  };
9628
9833
  }
9629
9834
 
9835
+ // src/internal/llm/tool-result-content.ts
9836
+ init_errors();
9837
+ function toBlockToolResultContent(content) {
9838
+ return content;
9839
+ }
9840
+ function toStringToolResultContent(content, providerName) {
9841
+ if (typeof content === "string") return content;
9842
+ if (content.some((block) => block.type === "image")) {
9843
+ throw new ConfigurationError(
9844
+ `provider "${providerName}" does not support image content in tool results`
9845
+ );
9846
+ }
9847
+ return content.filter(
9848
+ (block) => block.type === "text"
9849
+ ).map((block) => block.text).join("\n");
9850
+ }
9851
+ function renderToolResultContentText(content, fn) {
9852
+ if (typeof content === "string") return fn(content);
9853
+ return content.map(
9854
+ (block) => block.type === "text" ? { type: "text", text: fn(block.text) } : block
9855
+ );
9856
+ }
9857
+
9630
9858
  // src/internal/agent-loop/tool-result-guard.ts
9631
9859
  var OPEN = "<untrusted-tool-output>";
9632
9860
  var CLOSE = "</untrusted-tool-output>";
@@ -9652,7 +9880,11 @@ ${CLOSE}`;
9652
9880
  function applyToolResultGuard(parts, opts) {
9653
9881
  if (opts.delimit !== true && opts.redactPii !== true) return parts;
9654
9882
  return parts.map(
9655
- (p) => p.type === "tool_result" ? { ...p, content: guardText(p.content, opts) } : p
9883
+ (p) => (
9884
+ // SE7 — guard the TEXT of a tool result (string or the text blocks of a
9885
+ // structured content); image blocks pass through untouched.
9886
+ p.type === "tool_result" ? { ...p, content: renderToolResultContentText(p.content, (t) => guardText(t, opts)) } : p
9887
+ )
9656
9888
  );
9657
9889
  }
9658
9890
 
@@ -9991,6 +10223,14 @@ function computeUsageCost(inputs, usage) {
9991
10223
  }
9992
10224
 
9993
10225
  // src/internal/agent-loop/loop.ts
10226
+ function projectToolContextMessages(messages) {
10227
+ const projected = [];
10228
+ for (const m of messages) {
10229
+ const content = m.content.flatMap((p) => p.type === "text" ? [p.text] : []).join("");
10230
+ if (content !== "") projected.push({ role: m.role, content });
10231
+ }
10232
+ return projected;
10233
+ }
9994
10234
  var MAX_NUDGE_ATTEMPTS = 2;
9995
10235
  var MAX_STOP_FEEDBACK_ATTEMPTS = 2;
9996
10236
  async function runAgentLoop(inputs) {
@@ -10233,7 +10473,9 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
10233
10473
  const outText = await transformLlmOutputText(inputs, llmOutput.text, tCtx);
10234
10474
  ctx.messages.push(buildAssistantTurn(outText, llmOutput.toolCalls));
10235
10475
  const rawResults = await dispatchTools(
10236
- inputs,
10476
+ // SE12 — forward a read-only text projection of the transcript-so-far to tool
10477
+ // handlers via `ctx.messages` (consumed by defineSubAgent's messageFilter).
10478
+ { ...inputs, messages: projectToolContextMessages(ctx.messages) },
10237
10479
  ctx.tools,
10238
10480
  llmOutput.toolCalls,
10239
10481
  ctx.events,
@@ -10569,10 +10811,10 @@ function stripVertexPrefix(modelId) {
10569
10811
  }
10570
10812
 
10571
10813
  // src/internal/providers/builtin/index.ts
10572
- var registered2 = false;
10814
+ var registered3 = false;
10573
10815
  function registerBuiltins() {
10574
- if (registered2) return;
10575
- registered2 = true;
10816
+ if (registered3) return;
10817
+ registered3 = true;
10576
10818
  registerProvider(ANTHROPIC);
10577
10819
  registerProvider(OPENAI);
10578
10820
  registerProvider(OPENROUTER);
@@ -10800,7 +11042,9 @@ function toAnthropicWireMessage(message) {
10800
11042
  return {
10801
11043
  type: "tool_result",
10802
11044
  tool_use_id: part.toolUseId,
10803
- content: part.content,
11045
+ // SE7 — this wire is block-capable: strings pass through, structured
11046
+ // text/image blocks are forwarded natively.
11047
+ content: toBlockToolResultContent(part.content),
10804
11048
  ...part.isError === true ? { is_error: true } : {}
10805
11049
  };
10806
11050
  });
@@ -11592,7 +11836,8 @@ function toOllamaMessages(message) {
11592
11836
  if (part.type === "tool_result") {
11593
11837
  out.push({
11594
11838
  role: "tool",
11595
- content: part.content,
11839
+ // SE7 — string-only tool role: text blocks flatten; image fails fast.
11840
+ content: toStringToolResultContent(part.content, "ollama"),
11596
11841
  tool_name: part.toolUseId
11597
11842
  });
11598
11843
  }
@@ -12129,7 +12374,9 @@ function userOrToolMessages(message) {
12129
12374
  out.push({
12130
12375
  role: "tool",
12131
12376
  tool_call_id: part.toolUseId,
12132
- content: part.content
12377
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
12378
+ // image block fails fast (ConfigurationError).
12379
+ content: toStringToolResultContent(part.content, "openai")
12133
12380
  });
12134
12381
  }
12135
12382
  }
@@ -13058,18 +13305,20 @@ function levenshtein(a, b) {
13058
13305
  function createRealLocalRun(options) {
13059
13306
  const { userText, id, startTime } = prepareRunContext(options.message);
13060
13307
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
13061
- const unusedFixtureScript = {
13308
+ const runScript = {
13062
13309
  events: [],
13063
13310
  finalStatus: "running",
13064
13311
  cancellable: false,
13065
- conversation: []
13312
+ conversation: [],
13313
+ // SE3 — carry the turn's provenance so buildResult forwards it onto RunResult.origin.
13314
+ ...options.sendOptions.origin !== void 0 ? { origin: options.sendOptions.origin } : {}
13066
13315
  };
13067
13316
  const handle = new RealLocalRun(
13068
13317
  {
13069
13318
  id,
13070
13319
  agentId: options.agentId,
13071
13320
  model: options.model,
13072
- script: unusedFixtureScript,
13321
+ script: runScript,
13073
13322
  supportedOps: supported,
13074
13323
  startTime
13075
13324
  },
@@ -13181,6 +13430,8 @@ function buildLoopInputs(options, runId, userText) {
13181
13430
  // M7 — forward SendOptions.context to the loop so every tool handler receives
13182
13431
  // it on `ctx.context` (shared run config set once, e.g. projectRoot).
13183
13432
  ...options.sendOptions.context !== void 0 ? { context: options.sendOptions.context } : {},
13433
+ // SE2 — forward the opt-in typed runtime-event sink to the loop.
13434
+ ...options.sendOptions.onRunEvent !== void 0 ? { runEventSink: options.sendOptions.onRunEvent } : {},
13184
13435
  // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
13185
13436
  // can enable them via SendOptions (not only internal AgentLoopInputs).
13186
13437
  ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
@@ -15873,7 +16124,7 @@ function wrapRunWithPostReplyHook(args) {
15873
16124
  async function executeSendLocked(inputs, message, options) {
15874
16125
  if (inputs.disposed) throw new AgentDisposedError(inputs.agentId);
15875
16126
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
15876
- inputs.applyModelOverride(options.model);
16127
+ inputs.applyModelOverride(normalizeModel(options.model));
15877
16128
  const userText = typeof message === "string" ? message : message.text;
15878
16129
  if (inputs.options.onBeforeSend !== void 0) {
15879
16130
  await inputs.options.onBeforeSend({
@@ -16025,7 +16276,7 @@ var LocalAgent = class {
16025
16276
  constructor(options) {
16026
16277
  this.agentId = options.agentId ?? generateLocalAgentId();
16027
16278
  this._telemetry = createTelemetry(options.telemetry);
16028
- this.model = options.model;
16279
+ this.model = normalizeModel(options.model);
16029
16280
  this.options = options;
16030
16281
  this.workspaceCwd = resolveCwd(options.local?.cwd);
16031
16282
  this.conversationStorage = options.conversationStorage;
@@ -16092,6 +16343,11 @@ var LocalAgent = class {
16092
16343
  hooks() {
16093
16344
  return this.hooksExecutor;
16094
16345
  }
16346
+ // SE9 — integrated structured output; delegates to the shared helper.
16347
+ generate(message, options) {
16348
+ const { apiKey, local } = this.options;
16349
+ return agentGenerate(this, this.model, apiKey, local, message, options);
16350
+ }
16095
16351
  async send(message, options = {}) {
16096
16352
  if (options.tools !== void 0 && options.tools.length > 0) {
16097
16353
  validateToolCatalog(options.tools);
@@ -16331,6 +16587,7 @@ function includesSetting(options, source) {
16331
16587
 
16332
16588
  // src/agent-helpers.ts
16333
16589
  async function runCreateUnderSpan(options, span) {
16590
+ options = { ...options, model: normalizeModel(options.model) };
16334
16591
  validateAgentOptions(options);
16335
16592
  validateCloudToolParity(options);
16336
16593
  await guardAgainstIdCollision(options);
@@ -16404,7 +16661,10 @@ async function createLocalAgent(options) {
16404
16661
  const willFlowToProvider = !isFixtureApiKey(apiKey) && !shouldUseRealLocalRuntime(apiKey);
16405
16662
  const shape = validateApiKeyShape(apiKey, {
16406
16663
  strict: willFlowToProvider,
16407
- ...willFlowToProvider ? { provider: providerFromModelId(options.model?.id) } : {}
16664
+ // `options.model` is already normalized by `runCreateUnderSpan`; `normalizeModel`
16665
+ // here is the idempotent narrowing of the widened public type (`{id}` passes
16666
+ // through by reference) — cleaner than an `as` cast.
16667
+ ...willFlowToProvider ? { provider: providerFromModelId(normalizeModel(options.model)?.id) } : {}
16408
16668
  });
16409
16669
  if (shape.malformed) {
16410
16670
  throw new AuthenticationError(shape.message, { code: "malformed_api_key" });
@@ -16470,6 +16730,10 @@ async function rehydrateExistingAgent(agentId, existing, options) {
16470
16730
  ...existing.options,
16471
16731
  ...options,
16472
16732
  ...mergedLocal !== void 0 ? { local: mergedLocal } : {},
16733
+ // SE8 — normalize a caller-supplied bare-string model override at this resume
16734
+ // boundary (Agent.resume never flows through runCreateUnderSpan). Cloud resume
16735
+ // honors it; local resume forces the persisted model below.
16736
+ model: normalizeModel(options.model ?? existing.options.model),
16473
16737
  mcpServers: void 0,
16474
16738
  agentId
16475
16739
  };
@@ -16836,6 +17100,7 @@ async function getOrCreateUncached(agentId, options) {
16836
17100
  }
16837
17101
  setAgentFacade({
16838
17102
  create: (options) => Agent.create(options),
17103
+ delete: (agentId) => Agent.delete(agentId),
16839
17104
  prompt: (message, options) => Agent.prompt(message, options),
16840
17105
  get: (agentId) => Agent.get(agentId),
16841
17106
  resume: (agentId, options) => Agent.resume(agentId, options),