@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/index.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 fs = require('fs');
5
7
  var path = require('path');
6
8
  var promises = require('fs/promises');
7
- var zod = require('zod');
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');
@@ -519,6 +519,256 @@ var init_errors = __esm({
519
519
  };
520
520
  }
521
521
  });
522
+ function toJsonSchema(schema, options = { unrepresentable: "any" }) {
523
+ return zod.toJSONSchema(schema, options);
524
+ }
525
+ var init_to_json_schema = __esm({
526
+ "src/internal/zod/to-json-schema.ts"() {
527
+ }
528
+ });
529
+ function requireZod() {
530
+ if (cachedZ !== void 0) return cachedZ;
531
+ const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
532
+ let mod;
533
+ try {
534
+ mod = r("zod");
535
+ } catch (cause) {
536
+ throw new exports.ConfigurationError(
537
+ 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
538
+ { code: "zod_not_installed", cause }
539
+ );
540
+ }
541
+ cachedZ = mod.z ?? mod;
542
+ return cachedZ;
543
+ }
544
+ function makeOutputTool(jsonSchema, onCapture) {
545
+ return {
546
+ name: "output",
547
+ description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
548
+ inputSchema: jsonSchema,
549
+ handler: (input) => {
550
+ const out = onCapture(input);
551
+ if (typeof out === "string") return out;
552
+ if (out instanceof Promise) return out;
553
+ return "";
554
+ }
555
+ };
556
+ }
557
+ function buildTransientAgentOptions(params) {
558
+ return {
559
+ model: params.model,
560
+ local: params.local,
561
+ tools: [params.outputTool],
562
+ systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
563
+ ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
564
+ ...params.providers !== void 0 ? { providers: params.providers } : {}
565
+ };
566
+ }
567
+ function extractUsage(result) {
568
+ const u = result.usage;
569
+ if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
570
+ return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
571
+ }
572
+ function buildToolPrompt(prompt) {
573
+ return `${prompt}
574
+
575
+ Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
576
+ }
577
+ function setupStructuredOutput(schema, maxRetries) {
578
+ const z8 = requireZod();
579
+ const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
580
+ return {
581
+ z: z8,
582
+ jsonSchema,
583
+ maxRetries: maxRetries ?? 1,
584
+ initialUsage: { inputTokens: 0, outputTokens: 0 }
585
+ };
586
+ }
587
+ async function disposeAndDeleteTransient(agent, deletor) {
588
+ await agent.dispose();
589
+ try {
590
+ await deletor(agent.agentId);
591
+ } catch {
592
+ }
593
+ }
594
+ var cachedZ;
595
+ var init_structured_output_helpers = __esm({
596
+ "src/internal/structured-output-helpers.ts"() {
597
+ init_errors();
598
+ init_to_json_schema();
599
+ }
600
+ });
601
+
602
+ // src/generate-object.ts
603
+ var generate_object_exports = {};
604
+ __export(generate_object_exports, {
605
+ GenerateObjectError: () => exports.GenerateObjectError,
606
+ generateObjectImpl: () => generateObjectImpl
607
+ });
608
+ function salvagePartial(schema, raw) {
609
+ if (typeof raw !== "object" || raw === null) return raw;
610
+ const shape = schema.shape;
611
+ if (shape === void 0 || typeof shape !== "object") return raw;
612
+ const rawObj = raw;
613
+ const out = {};
614
+ for (const [key2, fieldSchema] of Object.entries(shape)) {
615
+ if (typeof fieldSchema?.safeParse !== "function") continue;
616
+ const parsed = fieldSchema.safeParse(rawObj[key2]);
617
+ if (parsed.success) out[key2] = parsed.data;
618
+ }
619
+ return out;
620
+ }
621
+ async function runReasoningPhase(options, deps) {
622
+ const reasoningOptions = {
623
+ model: options.model,
624
+ local: options.local,
625
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
626
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
627
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
628
+ };
629
+ const reasoningAgent = await deps.create(reasoningOptions);
630
+ try {
631
+ const run = await reasoningAgent.send(options.prompt);
632
+ const result = await run.wait();
633
+ const text = result.result;
634
+ return typeof text === "string" ? text : options.prompt;
635
+ } finally {
636
+ await disposeAndDeleteTransient(reasoningAgent, deps.delete);
637
+ }
638
+ }
639
+ async function generateObjectImpl(options, deps) {
640
+ const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
641
+ options.schema,
642
+ options.maxRetries
643
+ );
644
+ let capturedRaw;
645
+ let lastUsage = initialUsage;
646
+ const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
647
+ class CaptureSentinel extends Error {
648
+ constructor(captured) {
649
+ super("generate-object-capture");
650
+ this.captured = captured;
651
+ }
652
+ captured;
653
+ [sentinel] = true;
654
+ }
655
+ const outputTool = makeOutputTool(jsonSchema, (input) => {
656
+ if (capturedRaw === void 0) {
657
+ capturedRaw = input;
658
+ }
659
+ throw new CaptureSentinel(input);
660
+ });
661
+ const reasoningText = options.structuringModel !== void 0 ? await runReasoningPhase(options, deps) : void 0;
662
+ const structuringModel = options.structuringModel ?? options.model;
663
+ const structuringPrompt = reasoningText ?? options.prompt;
664
+ const agentOptions = buildTransientAgentOptions({
665
+ model: structuringModel,
666
+ local: options.local,
667
+ outputTool,
668
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
669
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
670
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
671
+ });
672
+ const agent = await deps.create(agentOptions);
673
+ try {
674
+ const userMessage = buildToolPrompt(structuringPrompt);
675
+ let lastParseError;
676
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
677
+ capturedRaw = void 0;
678
+ const run = await agent.send(userMessage);
679
+ const result = await run.wait();
680
+ lastUsage = extractUsage(result);
681
+ if (capturedRaw === void 0) {
682
+ if (result.status === "error" && result.error !== void 0) {
683
+ throw new exports.GenerateObjectError(
684
+ "no_tool_call",
685
+ `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
686
+ result.error
687
+ );
688
+ }
689
+ if (attempt === maxRetries) {
690
+ throw new exports.GenerateObjectError(
691
+ "no_tool_call",
692
+ "The model returned text instead of calling the `output` tool."
693
+ );
694
+ }
695
+ continue;
696
+ }
697
+ const parsed = options.schema.safeParse(capturedRaw);
698
+ if (parsed.success) {
699
+ return {
700
+ object: parsed.data,
701
+ raw: capturedRaw,
702
+ usage: lastUsage,
703
+ finishReason: "tool_use"
704
+ };
705
+ }
706
+ lastParseError = parsed.error;
707
+ }
708
+ if (options.errorStrategy === "return-raw") {
709
+ return {
710
+ object: capturedRaw,
711
+ raw: capturedRaw,
712
+ usage: lastUsage,
713
+ finishReason: "tool_use"
714
+ };
715
+ }
716
+ if (options.errorStrategy === "return-partial") {
717
+ return {
718
+ object: salvagePartial(options.schema, capturedRaw),
719
+ raw: capturedRaw,
720
+ usage: lastUsage,
721
+ finishReason: "tool_use"
722
+ };
723
+ }
724
+ throw new exports.GenerateObjectError(
725
+ "parse_failed",
726
+ "Schema parse failed after all retries.",
727
+ lastParseError
728
+ );
729
+ } finally {
730
+ await disposeAndDeleteTransient(agent, deps.delete);
731
+ }
732
+ }
733
+ exports.GenerateObjectError = void 0;
734
+ var init_generate_object = __esm({
735
+ "src/generate-object.ts"() {
736
+ init_structured_output_helpers();
737
+ exports.GenerateObjectError = class extends Error {
738
+ name = "GenerateObjectError";
739
+ code;
740
+ cause;
741
+ constructor(code, message, cause) {
742
+ super(message);
743
+ this.code = code;
744
+ if (cause !== void 0) this.cause = cause;
745
+ }
746
+ };
747
+ }
748
+ });
749
+
750
+ // src/internal/runtime/registry/agent-factory-registry.ts
751
+ var agent_factory_registry_exports = {};
752
+ __export(agent_factory_registry_exports, {
753
+ getAgentFacade: () => getAgentFacade,
754
+ setAgentFacade: () => setAgentFacade
755
+ });
756
+ function setAgentFacade(facade) {
757
+ registered = facade;
758
+ }
759
+ function getAgentFacade() {
760
+ if (registered === void 0) {
761
+ throw new Error(
762
+ "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
763
+ );
764
+ }
765
+ return registered;
766
+ }
767
+ var registered;
768
+ var init_agent_factory_registry = __esm({
769
+ "src/internal/runtime/registry/agent-factory-registry.ts"() {
770
+ }
771
+ });
522
772
 
523
773
  // src/internal/persistence/cwd-mutex.ts
524
774
  function withCwdMutex(key2, fn) {
@@ -2789,29 +3039,6 @@ var init_judge_call = __esm({
2789
3039
  }
2790
3040
  });
2791
3041
 
2792
- // src/internal/runtime/registry/agent-factory-registry.ts
2793
- var agent_factory_registry_exports = {};
2794
- __export(agent_factory_registry_exports, {
2795
- getAgentFacade: () => getAgentFacade,
2796
- setAgentFacade: () => setAgentFacade
2797
- });
2798
- function setAgentFacade(facade) {
2799
- registered3 = facade;
2800
- }
2801
- function getAgentFacade() {
2802
- if (registered3 === void 0) {
2803
- throw new Error(
2804
- "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
2805
- );
2806
- }
2807
- return registered3;
2808
- }
2809
- var registered3;
2810
- var init_agent_factory_registry = __esm({
2811
- "src/internal/runtime/registry/agent-factory-registry.ts"() {
2812
- }
2813
- });
2814
-
2815
3042
  // src/internal/runtime/lifecycle/run-to-completion.ts
2816
3043
  var run_to_completion_exports = {};
2817
3044
  __export(run_to_completion_exports, {
@@ -2976,14 +3203,14 @@ async function forkAgentImpl(parent, options, deps) {
2976
3203
  return {
2977
3204
  result: result.result,
2978
3205
  toolCalls: [],
2979
- usage: extractUsage(result)
3206
+ usage: extractUsage2(result)
2980
3207
  };
2981
3208
  });
2982
3209
  } finally {
2983
3210
  await fork.dispose();
2984
3211
  }
2985
3212
  }
2986
- function extractUsage(result) {
3213
+ function extractUsage2(result) {
2987
3214
  if (typeof result !== "object" || result === null) {
2988
3215
  return { inputTokens: 0, outputTokens: 0 };
2989
3216
  }
@@ -3614,331 +3841,104 @@ async function submit(internal) {
3614
3841
  once: true
3615
3842
  });
3616
3843
  }
3617
- const release = await acquireSlot();
3618
- void (async () => {
3619
- try {
3620
- await checkCancelRequestedAt(resolvedId, aborter);
3621
- if (aborter.signal.aborted) {
3622
- const cancelledAt = Date.now();
3623
- await transition(resolvedId, "cancelled", { cancelledAt });
3624
- emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
3625
- return;
3626
- }
3627
- const startedAt = Date.now();
3628
- await transition(resolvedId, "running", { startedAt });
3629
- emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
3630
- await runWorkAndFinalize(resolvedId, aborter, internal.work);
3631
- } finally {
3632
- release();
3633
- state.aborters.delete(resolvedId);
3634
- }
3635
- })();
3636
- return queuedHandle;
3637
- }
3638
- async function list(filter = {}) {
3639
- return state.store.list(filter);
3640
- }
3641
- async function get(id) {
3642
- if (!isValidTaskId(id, true)) return void 0;
3643
- return state.store.get(id);
3644
- }
3645
- async function cancel(id, reason) {
3646
- if (!isValidTaskId(id, true)) return { cancelled: false, alreadyTerminal: false };
3647
- const handle = await state.store.get(id);
3648
- if (handle === void 0) return { cancelled: false, alreadyTerminal: false };
3649
- if (handle.state === "finished" || handle.state === "error" || handle.state === "cancelled") {
3650
- return { cancelled: false, alreadyTerminal: true };
3651
- }
3652
- const span = startTaskCancelSpan({
3653
- taskId: id,
3654
- ...reason !== void 0 ? { reason } : {},
3655
- via: "api"
3656
- });
3657
- try {
3658
- return await cancelInternal(id, handle.state, reason);
3659
- } finally {
3660
- span.end();
3661
- }
3662
- }
3663
- async function cancelInternal(id, currentState, reason) {
3664
- if (currentState === "queued") {
3665
- const cancelledAt = Date.now();
3666
- await transition(id, "cancelled", { cancelledAt });
3667
- emitToSubscribers(id, {
3668
- type: "cancelled",
3669
- taskId: id,
3670
- cancelledAt,
3671
- ...reason !== void 0 ? { reason } : {}
3672
- });
3673
- state.aborters.delete(id);
3674
- return { cancelled: true, alreadyTerminal: false };
3675
- }
3676
- const aborter = state.aborters.get(id);
3677
- if (aborter !== void 0) aborter.abort(reason ?? "cancelled");
3678
- return { cancelled: true, alreadyTerminal: false };
3679
- }
3680
- async function evictNow(now = Date.now()) {
3681
- return state.store.evictTerminalOlderThan(now - state.retentionMs);
3682
- }
3683
- var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state, subscribe;
3684
- var init_registry = __esm({
3685
- "src/internal/task/registry.ts"() {
3686
- init_errors();
3687
- init_task();
3688
- init_async_semaphore();
3689
- init_ring_buffer();
3690
- init_store();
3691
- init_subscribe();
3692
- init_telemetry();
3693
- DEFAULT_CONCURRENCY = 8;
3694
- DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
3695
- EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
3696
- RING_CAP = 64;
3697
- reentryAls = new async_hooks.AsyncLocalStorage();
3698
- state = buildState({});
3699
- subscribe = buildSubscribe({
3700
- getBuffer: (id) => state.buffers.get(id),
3701
- getOrCreateSubscriberSet: (id) => {
3702
- let subs = state.subscribers.get(id);
3703
- if (subs === void 0) {
3704
- subs = /* @__PURE__ */ new Set();
3705
- state.subscribers.set(id, subs);
3706
- }
3707
- return subs;
3708
- },
3709
- removeSubscriber: (id, cb) => {
3710
- const set = state.subscribers.get(id);
3711
- set?.delete(cb);
3712
- if (set !== void 0 && set.size === 0) state.subscribers.delete(id);
3713
- }
3714
- });
3715
- }
3716
- });
3717
- function toJsonSchema(schema, options = { unrepresentable: "any" }) {
3718
- return zod.toJSONSchema(schema, options);
3719
- }
3720
- var init_to_json_schema = __esm({
3721
- "src/internal/zod/to-json-schema.ts"() {
3722
- }
3723
- });
3724
- function requireZod() {
3725
- if (cachedZ !== void 0) return cachedZ;
3726
- const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
3727
- let mod;
3728
- try {
3729
- mod = r("zod");
3730
- } catch (cause) {
3731
- throw new exports.ConfigurationError(
3732
- 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
3733
- { code: "zod_not_installed", cause }
3734
- );
3735
- }
3736
- cachedZ = mod.z ?? mod;
3737
- return cachedZ;
3738
- }
3739
- function makeOutputTool(jsonSchema, onCapture) {
3740
- return {
3741
- name: "output",
3742
- description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
3743
- inputSchema: jsonSchema,
3744
- handler: (input) => {
3745
- const out = onCapture(input);
3746
- if (typeof out === "string") return out;
3747
- if (out instanceof Promise) return out;
3748
- return "";
3749
- }
3750
- };
3751
- }
3752
- function buildTransientAgentOptions(params) {
3753
- return {
3754
- model: params.model,
3755
- local: params.local,
3756
- tools: [params.outputTool],
3757
- systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
3758
- ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
3759
- ...params.providers !== void 0 ? { providers: params.providers } : {}
3760
- };
3761
- }
3762
- function extractUsage2(result) {
3763
- const u = result.usage;
3764
- if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
3765
- return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
3766
- }
3767
- function buildToolPrompt(prompt) {
3768
- return `${prompt}
3769
-
3770
- Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
3771
- }
3772
- function setupStructuredOutput(schema, maxRetries) {
3773
- const z8 = requireZod();
3774
- const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
3775
- return {
3776
- z: z8,
3777
- jsonSchema,
3778
- maxRetries: maxRetries ?? 1,
3779
- initialUsage: { inputTokens: 0, outputTokens: 0 }
3780
- };
3781
- }
3782
- async function disposeAndDeleteTransient(agent, deletor) {
3783
- await agent.dispose();
3784
- try {
3785
- await deletor(agent.agentId);
3786
- } catch {
3787
- }
3788
- }
3789
- var cachedZ;
3790
- var init_structured_output_helpers = __esm({
3791
- "src/internal/structured-output-helpers.ts"() {
3792
- init_errors();
3793
- init_to_json_schema();
3794
- }
3795
- });
3796
-
3797
- // src/generate-object.ts
3798
- var generate_object_exports = {};
3799
- __export(generate_object_exports, {
3800
- GenerateObjectError: () => exports.GenerateObjectError,
3801
- generateObjectImpl: () => generateObjectImpl
3802
- });
3803
- function salvagePartial(schema, raw) {
3804
- if (typeof raw !== "object" || raw === null) return raw;
3805
- const shape = schema.shape;
3806
- if (shape === void 0 || typeof shape !== "object") return raw;
3807
- const rawObj = raw;
3808
- const out = {};
3809
- for (const [key2, fieldSchema] of Object.entries(shape)) {
3810
- if (typeof fieldSchema?.safeParse !== "function") continue;
3811
- const parsed = fieldSchema.safeParse(rawObj[key2]);
3812
- if (parsed.success) out[key2] = parsed.data;
3813
- }
3814
- return out;
3815
- }
3816
- async function runReasoningPhase(options, deps) {
3817
- const reasoningOptions = {
3818
- model: options.model,
3819
- local: options.local,
3820
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
3821
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
3822
- ...options.providers !== void 0 ? { providers: options.providers } : {}
3823
- };
3824
- const reasoningAgent = await deps.create(reasoningOptions);
3825
- try {
3826
- const run = await reasoningAgent.send(options.prompt);
3827
- const result = await run.wait();
3828
- const text = result.result;
3829
- return typeof text === "string" ? text : options.prompt;
3830
- } finally {
3831
- await disposeAndDeleteTransient(reasoningAgent, deps.delete);
3832
- }
3833
- }
3834
- async function generateObjectImpl(options, deps) {
3835
- const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
3836
- options.schema,
3837
- options.maxRetries
3838
- );
3839
- let capturedRaw;
3840
- let lastUsage = initialUsage;
3841
- const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
3842
- class CaptureSentinel extends Error {
3843
- constructor(captured) {
3844
- super("generate-object-capture");
3845
- this.captured = captured;
3846
- }
3847
- captured;
3848
- [sentinel] = true;
3849
- }
3850
- const outputTool = makeOutputTool(jsonSchema, (input) => {
3851
- if (capturedRaw === void 0) {
3852
- capturedRaw = input;
3853
- }
3854
- throw new CaptureSentinel(input);
3855
- });
3856
- const reasoningText = options.structuringModel !== void 0 ? await runReasoningPhase(options, deps) : void 0;
3857
- const structuringModel = options.structuringModel ?? options.model;
3858
- const structuringPrompt = reasoningText ?? options.prompt;
3859
- const agentOptions = buildTransientAgentOptions({
3860
- model: structuringModel,
3861
- local: options.local,
3862
- outputTool,
3863
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
3864
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
3865
- ...options.providers !== void 0 ? { providers: options.providers } : {}
3866
- });
3867
- const agent = await deps.create(agentOptions);
3868
- try {
3869
- const userMessage = buildToolPrompt(structuringPrompt);
3870
- let lastParseError;
3871
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
3872
- capturedRaw = void 0;
3873
- const run = await agent.send(userMessage);
3874
- const result = await run.wait();
3875
- lastUsage = extractUsage2(result);
3876
- if (capturedRaw === void 0) {
3877
- if (result.status === "error" && result.error !== void 0) {
3878
- throw new exports.GenerateObjectError(
3879
- "no_tool_call",
3880
- `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
3881
- result.error
3882
- );
3883
- }
3884
- if (attempt === maxRetries) {
3885
- throw new exports.GenerateObjectError(
3886
- "no_tool_call",
3887
- "The model returned text instead of calling the `output` tool."
3888
- );
3889
- }
3890
- continue;
3891
- }
3892
- const parsed = options.schema.safeParse(capturedRaw);
3893
- if (parsed.success) {
3894
- return {
3895
- object: parsed.data,
3896
- raw: capturedRaw,
3897
- usage: lastUsage,
3898
- finishReason: "tool_use"
3899
- };
3844
+ const release = await acquireSlot();
3845
+ void (async () => {
3846
+ try {
3847
+ await checkCancelRequestedAt(resolvedId, aborter);
3848
+ if (aborter.signal.aborted) {
3849
+ const cancelledAt = Date.now();
3850
+ await transition(resolvedId, "cancelled", { cancelledAt });
3851
+ emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
3852
+ return;
3900
3853
  }
3901
- lastParseError = parsed.error;
3902
- }
3903
- if (options.errorStrategy === "return-raw") {
3904
- return {
3905
- object: capturedRaw,
3906
- raw: capturedRaw,
3907
- usage: lastUsage,
3908
- finishReason: "tool_use"
3909
- };
3910
- }
3911
- if (options.errorStrategy === "return-partial") {
3912
- return {
3913
- object: salvagePartial(options.schema, capturedRaw),
3914
- raw: capturedRaw,
3915
- usage: lastUsage,
3916
- finishReason: "tool_use"
3917
- };
3854
+ const startedAt = Date.now();
3855
+ await transition(resolvedId, "running", { startedAt });
3856
+ emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
3857
+ await runWorkAndFinalize(resolvedId, aborter, internal.work);
3858
+ } finally {
3859
+ release();
3860
+ state.aborters.delete(resolvedId);
3918
3861
  }
3919
- throw new exports.GenerateObjectError(
3920
- "parse_failed",
3921
- "Schema parse failed after all retries.",
3922
- lastParseError
3923
- );
3862
+ })();
3863
+ return queuedHandle;
3864
+ }
3865
+ async function list(filter = {}) {
3866
+ return state.store.list(filter);
3867
+ }
3868
+ async function get(id) {
3869
+ if (!isValidTaskId(id, true)) return void 0;
3870
+ return state.store.get(id);
3871
+ }
3872
+ async function cancel(id, reason) {
3873
+ if (!isValidTaskId(id, true)) return { cancelled: false, alreadyTerminal: false };
3874
+ const handle = await state.store.get(id);
3875
+ if (handle === void 0) return { cancelled: false, alreadyTerminal: false };
3876
+ if (handle.state === "finished" || handle.state === "error" || handle.state === "cancelled") {
3877
+ return { cancelled: false, alreadyTerminal: true };
3878
+ }
3879
+ const span = startTaskCancelSpan({
3880
+ taskId: id,
3881
+ ...reason !== void 0 ? { reason } : {},
3882
+ via: "api"
3883
+ });
3884
+ try {
3885
+ return await cancelInternal(id, handle.state, reason);
3924
3886
  } finally {
3925
- await disposeAndDeleteTransient(agent, deps.delete);
3887
+ span.end();
3926
3888
  }
3927
3889
  }
3928
- exports.GenerateObjectError = void 0;
3929
- var init_generate_object = __esm({
3930
- "src/generate-object.ts"() {
3931
- init_structured_output_helpers();
3932
- exports.GenerateObjectError = class extends Error {
3933
- name = "GenerateObjectError";
3934
- code;
3935
- cause;
3936
- constructor(code, message, cause) {
3937
- super(message);
3938
- this.code = code;
3939
- if (cause !== void 0) this.cause = cause;
3890
+ async function cancelInternal(id, currentState, reason) {
3891
+ if (currentState === "queued") {
3892
+ const cancelledAt = Date.now();
3893
+ await transition(id, "cancelled", { cancelledAt });
3894
+ emitToSubscribers(id, {
3895
+ type: "cancelled",
3896
+ taskId: id,
3897
+ cancelledAt,
3898
+ ...reason !== void 0 ? { reason } : {}
3899
+ });
3900
+ state.aborters.delete(id);
3901
+ return { cancelled: true, alreadyTerminal: false };
3902
+ }
3903
+ const aborter = state.aborters.get(id);
3904
+ if (aborter !== void 0) aborter.abort(reason ?? "cancelled");
3905
+ return { cancelled: true, alreadyTerminal: false };
3906
+ }
3907
+ async function evictNow(now = Date.now()) {
3908
+ return state.store.evictTerminalOlderThan(now - state.retentionMs);
3909
+ }
3910
+ var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state, subscribe;
3911
+ var init_registry = __esm({
3912
+ "src/internal/task/registry.ts"() {
3913
+ init_errors();
3914
+ init_task();
3915
+ init_async_semaphore();
3916
+ init_ring_buffer();
3917
+ init_store();
3918
+ init_subscribe();
3919
+ init_telemetry();
3920
+ DEFAULT_CONCURRENCY = 8;
3921
+ DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
3922
+ EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
3923
+ RING_CAP = 64;
3924
+ reentryAls = new async_hooks.AsyncLocalStorage();
3925
+ state = buildState({});
3926
+ subscribe = buildSubscribe({
3927
+ getBuffer: (id) => state.buffers.get(id),
3928
+ getOrCreateSubscriberSet: (id) => {
3929
+ let subs = state.subscribers.get(id);
3930
+ if (subs === void 0) {
3931
+ subs = /* @__PURE__ */ new Set();
3932
+ state.subscribers.set(id, subs);
3933
+ }
3934
+ return subs;
3935
+ },
3936
+ removeSubscriber: (id, cb) => {
3937
+ const set = state.subscribers.get(id);
3938
+ set?.delete(cb);
3939
+ if (set !== void 0 && set.size === 0) state.subscribers.delete(id);
3940
3940
  }
3941
- };
3941
+ });
3942
3942
  }
3943
3943
  });
3944
3944
 
@@ -3996,7 +3996,7 @@ async function* streamObjectImpl(options, deps) {
3996
3996
  }
3997
3997
  }
3998
3998
  const result = await run.wait();
3999
- lastUsage = extractUsage2(result);
3999
+ lastUsage = extractUsage(result);
4000
4000
  if (capturedRaw === void 0) {
4001
4001
  if (result.status === "error" && result.error !== void 0) {
4002
4002
  throw new exports.StreamObjectError(
@@ -4748,7 +4748,10 @@ async function runAgentStep(step, input, ctx) {
4748
4748
  };
4749
4749
  }
4750
4750
  const exec = async () => {
4751
- const run = await step.agent.send(prompt);
4751
+ const run = await step.agent.send(
4752
+ prompt,
4753
+ step.origin !== void 0 ? { origin: step.origin } : void 0
4754
+ );
4752
4755
  const result = await run.wait();
4753
4756
  if (result.status === "finished") {
4754
4757
  return result.result ?? "";
@@ -5520,6 +5523,7 @@ var AgentBuilder = class {
5520
5523
  constructor(deps) {
5521
5524
  this.deps = deps;
5522
5525
  }
5526
+ /** SE8 — accepts a bare-string id shorthand (`"openai/gpt-4o-mini"`) or a {@link ModelSelection}. */
5523
5527
  model(m) {
5524
5528
  this.opts.model = m;
5525
5529
  return this;
@@ -5877,13 +5881,87 @@ function isLocalAgentId(id) {
5877
5881
  return id.startsWith(PREFIX.localAgent);
5878
5882
  }
5879
5883
 
5884
+ // src/internal/runtime/config/default-model.ts
5885
+ var DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
5886
+
5887
+ // src/agent-generate.ts
5888
+ async function agentGenerate(agent, agentModel, agentApiKey, agentLocal, input, options) {
5889
+ const { output, maxRetries, errorStrategy, ...sendOptions } = options;
5890
+ const run = await agent.send(input, sendOptions);
5891
+ const result = await run.wait();
5892
+ const { generateObjectImpl: generateObjectImpl2, GenerateObjectError: GenerateObjectError2 } = await Promise.resolve().then(() => (init_generate_object(), generate_object_exports));
5893
+ const answer = structurableAnswerOrThrow(result, GenerateObjectError2);
5894
+ const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
5895
+ const facade = getAgentFacade2();
5896
+ const structured = await generateObjectImpl2(
5897
+ {
5898
+ prompt: answer,
5899
+ schema: output,
5900
+ // `agentModel` arrives already normalized (`this.model` passed through
5901
+ // `normalizeModel` in the LocalAgent/CloudAgent constructor), so the widened
5902
+ // `string | ModelSelection` field only ever receives a `ModelSelection` here.
5903
+ model: agentModel ?? { id: DEFAULT_AGENTIC_MODEL_ID },
5904
+ // `local` is required to keep the transient structuring agent local-only;
5905
+ // default to the process cwd when the agent had no explicit local config.
5906
+ local: agentLocal ?? { cwd: process.cwd() },
5907
+ ...agentApiKey !== void 0 ? { apiKey: agentApiKey } : {},
5908
+ ...maxRetries !== void 0 ? { maxRetries } : {},
5909
+ ...errorStrategy !== void 0 ? { errorStrategy } : {}
5910
+ },
5911
+ {
5912
+ create: (opts) => facade.create(opts),
5913
+ delete: (agentId) => facade.delete(agentId)
5914
+ }
5915
+ );
5916
+ return {
5917
+ object: structured.object,
5918
+ result,
5919
+ raw: structured.raw,
5920
+ usage: structured.usage
5921
+ };
5922
+ }
5923
+ function structurableAnswerOrThrow(result, GenerateObjectError2) {
5924
+ if (result.status === "error") {
5925
+ throw new GenerateObjectError2(
5926
+ "no_tool_call",
5927
+ `Agent run failed before an answer could be structured: ${result.error?.message ?? "unknown error"} [${result.error?.code ?? "?"}]`,
5928
+ result.error
5929
+ );
5930
+ }
5931
+ if (result.status === "cancelled") {
5932
+ throw new GenerateObjectError2(
5933
+ "no_tool_call",
5934
+ "Agent run was cancelled before an answer could be structured."
5935
+ );
5936
+ }
5937
+ const answer = result.result;
5938
+ if (answer === void 0 || answer.length === 0) {
5939
+ throw new GenerateObjectError2(
5940
+ "no_tool_call",
5941
+ "The tool loop finished with no text answer (tool-only completion) \u2014 there is nothing to structure."
5942
+ );
5943
+ }
5944
+ return answer;
5945
+ }
5946
+
5880
5947
  // src/internal/runtime/cloud/cloud-agent.ts
5881
5948
  init_errors();
5882
5949
  init_cwd_mutex();
5883
5950
  init_path_guard();
5884
5951
 
5885
- // src/internal/runtime/config/default-model.ts
5886
- var DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
5952
+ // src/internal/runtime/model-selection.ts
5953
+ init_errors();
5954
+ function normalizeModel(m) {
5955
+ if (m === void 0 || typeof m !== "string") return m;
5956
+ const id = m.trim();
5957
+ if (id.length === 0) {
5958
+ throw new exports.ConfigurationError(
5959
+ 'model must be a non-empty "provider/model" id string or a ModelSelection object',
5960
+ { code: "invalid_model_selection" }
5961
+ );
5962
+ }
5963
+ return { id };
5964
+ }
5887
5965
 
5888
5966
  // src/internal/runtime/registry/agent-registry-store.ts
5889
5967
  init_cwd_mutex();
@@ -5960,7 +6038,10 @@ var REGISTRY_RELATIVE_PATH = path.join(".theokit", "agents", "registry.json");
5960
6038
  function stripSecretsFromOptions(options) {
5961
6039
  return assignDefined({
5962
6040
  name: options.name,
5963
- model: options.model !== void 0 ? { id: options.model.id } : void 0,
6041
+ model: (() => {
6042
+ const m = normalizeModel(options.model);
6043
+ return m !== void 0 ? { id: m.id } : void 0;
6044
+ })(),
5964
6045
  systemPrompt: typeof options.systemPrompt === "string" ? options.systemPrompt : void 0,
5965
6046
  local: serializeLocal(options.local),
5966
6047
  cloud: serializeCloud(options.cloud),
@@ -6245,7 +6326,8 @@ function serializeCloudAgentConfig(options) {
6245
6326
  cloud: serializeCloud2(options.cloud)
6246
6327
  };
6247
6328
  if (typeof options.agentId === "string") payload.agentId = options.agentId;
6248
- if (options.model !== void 0) payload.model = { id: options.model.id };
6329
+ const cfgModel = normalizeModel(options.model);
6330
+ if (cfgModel !== void 0) payload.model = { id: cfgModel.id };
6249
6331
  if (typeof options.systemPrompt === "string") payload.systemPrompt = options.systemPrompt;
6250
6332
  const skills = serializeSkills(options.skills);
6251
6333
  if (skills !== void 0) payload.skills = skills;
@@ -7050,6 +7132,7 @@ function applyScriptMetrics(base, script) {
7050
7132
  if (script.cost !== void 0) base.cost = script.cost;
7051
7133
  if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
7052
7134
  if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
7135
+ if (script.origin !== void 0) base.origin = script.origin;
7053
7136
  }
7054
7137
 
7055
7138
  // src/internal/runtime/cloud/cloud-run.ts
@@ -7405,7 +7488,7 @@ var CloudAgent = class {
7405
7488
  disposed = false;
7406
7489
  constructor(options, providedAgentId) {
7407
7490
  this.agentId = providedAgentId ?? options.agentId ?? generateCloudAgentId();
7408
- this.model = options.model;
7491
+ this.model = normalizeModel(options.model);
7409
7492
  this.options = options;
7410
7493
  this.cloudPayload = serializeCloudAgentConfig({ ...options, agentId: this.agentId });
7411
7494
  const repoUrls = (options.cloud?.repos ?? []).map((repo) => repo.url);
@@ -7435,6 +7518,17 @@ var CloudAgent = class {
7435
7518
  const apiKey = resolveApiKey(this.options.apiKey);
7436
7519
  return isFixtureApiKey(apiKey) && getConfiguredBaseUrl() === void 0;
7437
7520
  }
7521
+ // SE9 — integrated structured output; delegates to the shared helper.
7522
+ generate(message, options) {
7523
+ return agentGenerate(
7524
+ this,
7525
+ this.model,
7526
+ this.options.apiKey,
7527
+ this.options.local,
7528
+ message,
7529
+ options
7530
+ );
7531
+ }
7438
7532
  async send(message, options = {}) {
7439
7533
  if (options.tools !== void 0 && options.tools.length > 0) {
7440
7534
  throw new exports.ConfigurationError(
@@ -7465,7 +7559,7 @@ var CloudAgent = class {
7465
7559
  });
7466
7560
  }
7467
7561
  async sendLocked(message, options) {
7468
- const overrideModel = options.model;
7562
+ const overrideModel = normalizeModel(options.model);
7469
7563
  if (overrideModel !== void 0) {
7470
7564
  this.model = overrideModel;
7471
7565
  updateRegisteredAgent(this.agentId, { model: overrideModel });
@@ -8382,18 +8476,18 @@ var ALL_ADAPTERS = [
8382
8476
  arizeAdapter,
8383
8477
  braintrustAdapter
8384
8478
  ];
8385
- var registered = /* @__PURE__ */ new Set();
8479
+ var registered2 = /* @__PURE__ */ new Set();
8386
8480
  function tryAutoRegisterAdapters(settings) {
8387
8481
  if (settings?.enabled !== true) return;
8388
8482
  if (settings.autoDetect === false) return;
8389
8483
  const disabled = new Set(settings.disable ?? []);
8390
8484
  for (const adapter of ALL_ADAPTERS) {
8391
- if (registered.has(adapter.moduleName)) continue;
8485
+ if (registered2.has(adapter.moduleName)) continue;
8392
8486
  if (disabled.has(adapter.displayName.toLowerCase())) continue;
8393
8487
  if (!adapter.detect()) continue;
8394
8488
  try {
8395
8489
  adapter.register();
8396
- registered.add(adapter.moduleName);
8490
+ registered2.add(adapter.moduleName);
8397
8491
  process.stderr.write(`[theokit-sdk] telemetry: ${adapter.displayName} auto-instrumented.
8398
8492
  `);
8399
8493
  } catch (cause) {
@@ -8923,6 +9017,26 @@ function paginate(items, opts) {
8923
9017
  return items.slice(start, end);
8924
9018
  }
8925
9019
 
9020
+ // src/internal/persistence/session-meta.ts
9021
+ function applyMetaPatch(current, patch) {
9022
+ const next = {};
9023
+ if (current.title !== void 0) next.title = current.title;
9024
+ if (current.tag !== void 0) next.tag = current.tag;
9025
+ if (patch.title === null) delete next.title;
9026
+ else if (patch.title !== void 0) next.title = patch.title;
9027
+ if (patch.tag === null) delete next.tag;
9028
+ else if (patch.tag !== void 0) next.tag = patch.tag;
9029
+ return next;
9030
+ }
9031
+ function coerceSessionMeta(raw) {
9032
+ if (typeof raw !== "object" || raw === null) return void 0;
9033
+ const obj = raw;
9034
+ const meta = {};
9035
+ if (typeof obj.title === "string") meta.title = obj.title;
9036
+ if (typeof obj.tag === "string") meta.tag = obj.tag;
9037
+ return meta.title === void 0 && meta.tag === void 0 ? void 0 : meta;
9038
+ }
9039
+
8926
9040
  // src/internal/persistence/conversation-storage-fs.ts
8927
9041
  var FileSystemConversationStorage = class {
8928
9042
  #root;
@@ -8973,6 +9087,37 @@ var FileSystemConversationStorage = class {
8973
9087
  async compact(conversationId, maxTurns) {
8974
9088
  await compactSessionFile(this.#root, conversationId, maxTurns);
8975
9089
  }
9090
+ // SE4 — session metadata persisted as a per-conversation sidecar
9091
+ // `<root>/.theokit/agents/<safeId>/session.json` (same sanitized perimeter as
9092
+ // the transcript). Kept separate from messages.jsonl so a title/tag write does
9093
+ // not rewrite the append-only log.
9094
+ #metaPath(conversationId) {
9095
+ const safe2 = sanitizeIdentifier(conversationId, { maxLen: 128 });
9096
+ return safePathJoin(this.#root, ".theokit", "agents", safe2, "session.json");
9097
+ }
9098
+ async getSessionMeta(conversationId) {
9099
+ try {
9100
+ const raw = await promises.readFile(this.#metaPath(conversationId), "utf8");
9101
+ return coerceSessionMeta(JSON.parse(raw));
9102
+ } catch (cause) {
9103
+ if (cause.code === "ENOENT") return void 0;
9104
+ throw cause;
9105
+ }
9106
+ }
9107
+ async setSessionMeta(conversationId, patch) {
9108
+ const metaPath = this.#metaPath(conversationId);
9109
+ await promises.mkdir(path.dirname(metaPath), { recursive: true });
9110
+ await withFileLock(metaPath, async () => {
9111
+ let current = {};
9112
+ try {
9113
+ current = coerceSessionMeta(JSON.parse(await promises.readFile(metaPath, "utf8"))) ?? {};
9114
+ } catch (cause) {
9115
+ if (cause.code !== "ENOENT") throw cause;
9116
+ }
9117
+ const next = applyMetaPatch(current, patch);
9118
+ await promises.writeFile(metaPath, redactSecrets(JSON.stringify(next)), "utf8");
9119
+ });
9120
+ }
8976
9121
  async dispose() {
8977
9122
  }
8978
9123
  };
@@ -10894,7 +11039,7 @@ function bootstrapSubmanagers(args) {
10894
11039
  const providerCount = (args.options.providers?.routes?.length ?? 0) + enabledPluginNames(args.options.plugins).length;
10895
11040
  if (providerCount > 0 || args.options.providers !== void 0) {
10896
11041
  out.providers = new ProvidersManagerImpl(
10897
- args.options.model,
11042
+ normalizeModel(args.options.model),
10898
11043
  args.options.providers,
10899
11044
  args.options.plugins
10900
11045
  );
@@ -10964,6 +11109,7 @@ function createLocalRun(options) {
10964
11109
  projectMcpServers: options.projectMcpServers,
10965
11110
  ...options.persistMemoryFact !== void 0 ? { persistMemoryFact: options.persistMemoryFact } : {}
10966
11111
  });
11112
+ if (options.sendOptions.origin !== void 0) script.origin = options.sendOptions.origin;
10967
11113
  const handle = new LocalRun({
10968
11114
  id,
10969
11115
  agentId: options.agentId,
@@ -11612,6 +11758,15 @@ async function emitReasoningDeltaCallback(inputs, text) {
11612
11758
  );
11613
11759
  }
11614
11760
 
11761
+ // src/types/run-events.ts
11762
+ function emitRunEvent(sink, event) {
11763
+ if (sink === void 0) return;
11764
+ try {
11765
+ sink(event);
11766
+ } catch {
11767
+ }
11768
+ }
11769
+
11615
11770
  // src/internal/agent-loop/tool-dispatch.ts
11616
11771
  init_async_local_storage();
11617
11772
 
@@ -11709,6 +11864,22 @@ function coerceArgsToSchema(args, schema) {
11709
11864
  return { value: out, changed };
11710
11865
  }
11711
11866
 
11867
+ // src/tool-error.ts
11868
+ init_errors();
11869
+ var ToolError = class extends exports.TheokitAgentError {
11870
+ name = "ToolError";
11871
+ /** The error content surfaced to the model: a string, or text/image blocks. */
11872
+ content;
11873
+ constructor(content, options = {}) {
11874
+ super(renderToolErrorMessage(content), { ...options, isRetryable: false });
11875
+ this.content = content;
11876
+ }
11877
+ };
11878
+ function renderToolErrorMessage(content) {
11879
+ if (typeof content === "string") return content;
11880
+ return content.map((block) => block.type === "text" ? block.text : `[${block.source.media_type} image]`).join("\n");
11881
+ }
11882
+
11712
11883
  // src/internal/runtime/tools/shell-tool.ts
11713
11884
  async function runShell(options) {
11714
11885
  if (options.sandbox === true && isObviouslyUnsafe(options.command)) {
@@ -11748,23 +11919,27 @@ async function executeTool(inputs, resolved, call) {
11748
11919
  if (resolved.origin === "shell") return runShellTool(inputs, call);
11749
11920
  if (resolved.origin === "memory") return runMemoryTool(resolved, call, inputs.context);
11750
11921
  if (resolved.origin === "custom")
11751
- return runCustomTool(resolved, call, inputs.signal, inputs.context);
11922
+ return runCustomTool(resolved, call, inputs.signal, inputs.context, inputs.messages);
11752
11923
  return runMcpTool(inputs, resolved, call);
11753
11924
  }
11754
11925
  async function runMemoryTool(resolved, call, context) {
11755
11926
  return runHandlerTool("memory", resolved.memoryHandler, call, void 0, context);
11756
11927
  }
11757
- async function runCustomTool(resolved, call, signal, context) {
11758
- return runHandlerTool("custom", resolved.customHandler, call, signal, context);
11928
+ async function runCustomTool(resolved, call, signal, context, messages) {
11929
+ return runHandlerTool("custom", resolved.customHandler, call, signal, context, messages);
11759
11930
  }
11760
- async function runHandlerTool(kind, handler, call, signal, context) {
11931
+ async function runHandlerTool(kind, handler, call, signal, context, messages) {
11761
11932
  if (handler === void 0) {
11762
11933
  return { stdout: "", stderr: `${kind} tool ${call.name} has no handler`, exitCode: 127 };
11763
11934
  }
11764
11935
  try {
11765
- const stdout = await handler(call.input, { signal, context });
11766
- return { stdout, stderr: "", exitCode: 0 };
11936
+ const out = await handler(call.input, { signal, context, messages });
11937
+ if (typeof out !== "string") return { stdout: "", stderr: "", exitCode: 0, content: out };
11938
+ return { stdout: out, stderr: "", exitCode: 0 };
11767
11939
  } catch (cause) {
11940
+ if (cause instanceof ToolError) {
11941
+ return { stdout: "", stderr: cause.message, exitCode: 1, content: cause.content };
11942
+ }
11768
11943
  const message = cause instanceof Error ? cause.message : String(cause);
11769
11944
  return { stdout: "", stderr: message, exitCode: 1 };
11770
11945
  }
@@ -11883,6 +12058,11 @@ async function dispatchSingleCall(inputs, tools, call, events, parentSpan) {
11883
12058
  toolSpan?.end();
11884
12059
  return fileVeto;
11885
12060
  }
12061
+ emitRunEvent(inputs.runEventSink, {
12062
+ type: "tool_progress",
12063
+ toolName: workingCall.name,
12064
+ toolCallId: callId
12065
+ });
11886
12066
  const result = await runToolWithLifecycle(inputs, resolved, workingCall, callId);
11887
12067
  await inputs.pluginManager?.runPostToolCallHooks({
11888
12068
  name: workingCall.name,
@@ -11909,6 +12089,13 @@ function applyRepairAndExtractCall(tools, call) {
11909
12089
  function vetoFromForkWhitelist(inputs, call, callId, events) {
11910
12090
  const whitelistDecision = checkToolWhitelist(call.name);
11911
12091
  if (whitelistDecision.allowed) return void 0;
12092
+ emitRunEvent(inputs.runEventSink, {
12093
+ type: "permission_denied",
12094
+ toolName: call.name,
12095
+ toolCallId: callId,
12096
+ source: "fork_whitelist",
12097
+ message: whitelistDecision.reason ?? "tool not available in fork"
12098
+ });
11912
12099
  events.push(buildToolUseRunning(inputs, callId, call));
11913
12100
  events.push(
11914
12101
  buildToolUseCompleted(inputs, callId, call, {
@@ -11945,6 +12132,13 @@ async function vetoFromPluginPreHook(inputs, call, callId, events) {
11945
12132
  runId: inputs.runId
11946
12133
  });
11947
12134
  if (pluginVeto === void 0) return void 0;
12135
+ emitRunEvent(inputs.runEventSink, {
12136
+ type: "permission_denied",
12137
+ toolName: call.name,
12138
+ toolCallId: callId,
12139
+ source: "plugin",
12140
+ message: pluginVeto.message
12141
+ });
11948
12142
  events.push(
11949
12143
  buildToolUseCompleted(inputs, callId, call, {
11950
12144
  stdout: "",
@@ -11967,6 +12161,13 @@ async function vetoFromFileHookPreDecision(inputs, call, callId, events) {
11967
12161
  runId: inputs.runId
11968
12162
  });
11969
12163
  if (!preDecision.blocked) return void 0;
12164
+ emitRunEvent(inputs.runEventSink, {
12165
+ type: "permission_denied",
12166
+ toolName: call.name,
12167
+ toolCallId: callId,
12168
+ source: "file_hook",
12169
+ message: preDecision.reason ?? "blocked by hook"
12170
+ });
11970
12171
  events.push(
11971
12172
  buildToolUseCompleted(inputs, callId, call, {
11972
12173
  stdout: "",
@@ -12010,7 +12211,9 @@ async function runToolWithLifecycle(inputs, resolved, call, callId) {
12010
12211
  await safeEmitToolHook(inputs.onToolEnd, {
12011
12212
  toolName: call.name,
12012
12213
  args: call.input,
12013
- result: result.stdout,
12214
+ // SE7 — a block-returning handler has empty `stdout`; surface its structured
12215
+ // content to the hook instead of an empty string.
12216
+ result: result.content !== void 0 ? result.content : result.stdout,
12014
12217
  conversationId: inputs.agentId,
12015
12218
  callId,
12016
12219
  durationMs
@@ -12032,7 +12235,10 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
12032
12235
  output: {
12033
12236
  stdout: result.stdout,
12034
12237
  stderr: result.stderr,
12035
- exitCode: result.exitCode ?? 0
12238
+ exitCode: result.exitCode ?? 0,
12239
+ // SE7 — structured content (text + image blocks) when the handler
12240
+ // returned/threw blocks; absent for the string path.
12241
+ ...result.content !== void 0 ? { content: result.content } : {}
12036
12242
  },
12037
12243
  agentId: inputs.agentId,
12038
12244
  runId: inputs.runId
@@ -12045,7 +12251,9 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
12045
12251
  return {
12046
12252
  type: "tool_result",
12047
12253
  toolUseId: call.id,
12048
- content: renderToolResult(result),
12254
+ // SE7 — structured content blocks (handler-returned or ToolError-carried)
12255
+ // are authoritative; otherwise the legacy string rendering.
12256
+ content: result.content !== void 0 ? result.content : renderToolResult(result),
12049
12257
  ...result.exitCode !== 0 && result.exitCode !== void 0 ? { isError: true } : {}
12050
12258
  };
12051
12259
  }
@@ -12094,6 +12302,29 @@ function buildToolUseCompleted(inputs, callId, call, result) {
12094
12302
  };
12095
12303
  }
12096
12304
 
12305
+ // src/internal/llm/tool-result-content.ts
12306
+ init_errors();
12307
+ function toBlockToolResultContent(content) {
12308
+ return content;
12309
+ }
12310
+ function toStringToolResultContent(content, providerName) {
12311
+ if (typeof content === "string") return content;
12312
+ if (content.some((block) => block.type === "image")) {
12313
+ throw new exports.ConfigurationError(
12314
+ `provider "${providerName}" does not support image content in tool results`
12315
+ );
12316
+ }
12317
+ return content.filter(
12318
+ (block) => block.type === "text"
12319
+ ).map((block) => block.text).join("\n");
12320
+ }
12321
+ function renderToolResultContentText(content, fn) {
12322
+ if (typeof content === "string") return fn(content);
12323
+ return content.map(
12324
+ (block) => block.type === "text" ? { type: "text", text: fn(block.text) } : block
12325
+ );
12326
+ }
12327
+
12097
12328
  // src/internal/agent-loop/tool-result-guard.ts
12098
12329
  var OPEN = "<untrusted-tool-output>";
12099
12330
  var CLOSE = "</untrusted-tool-output>";
@@ -12119,7 +12350,11 @@ ${CLOSE}`;
12119
12350
  function applyToolResultGuard(parts, opts) {
12120
12351
  if (opts.delimit !== true && opts.redactPii !== true) return parts;
12121
12352
  return parts.map(
12122
- (p) => p.type === "tool_result" ? { ...p, content: guardText(p.content, opts) } : p
12353
+ (p) => (
12354
+ // SE7 — guard the TEXT of a tool result (string or the text blocks of a
12355
+ // structured content); image blocks pass through untouched.
12356
+ p.type === "tool_result" ? { ...p, content: renderToolResultContentText(p.content, (t) => guardText(t, opts)) } : p
12357
+ )
12123
12358
  );
12124
12359
  }
12125
12360
 
@@ -12458,6 +12693,14 @@ function computeUsageCost(inputs, usage) {
12458
12693
  }
12459
12694
 
12460
12695
  // src/internal/agent-loop/loop.ts
12696
+ function projectToolContextMessages(messages) {
12697
+ const projected = [];
12698
+ for (const m of messages) {
12699
+ const content = m.content.flatMap((p) => p.type === "text" ? [p.text] : []).join("");
12700
+ if (content !== "") projected.push({ role: m.role, content });
12701
+ }
12702
+ return projected;
12703
+ }
12461
12704
  var MAX_NUDGE_ATTEMPTS = 2;
12462
12705
  var MAX_STOP_FEEDBACK_ATTEMPTS = 2;
12463
12706
  async function runAgentLoop(inputs) {
@@ -12700,7 +12943,9 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
12700
12943
  const outText = await transformLlmOutputText(inputs, llmOutput.text, tCtx);
12701
12944
  ctx.messages.push(buildAssistantTurn(outText, llmOutput.toolCalls));
12702
12945
  const rawResults = await dispatchTools(
12703
- inputs,
12946
+ // SE12 — forward a read-only text projection of the transcript-so-far to tool
12947
+ // handlers via `ctx.messages` (consumed by defineSubAgent's messageFilter).
12948
+ { ...inputs, messages: projectToolContextMessages(ctx.messages) },
12704
12949
  ctx.tools,
12705
12950
  llmOutput.toolCalls,
12706
12951
  ctx.events,
@@ -13050,10 +13295,10 @@ function stripVertexPrefix(modelId) {
13050
13295
  }
13051
13296
 
13052
13297
  // src/internal/providers/builtin/index.ts
13053
- var registered2 = false;
13298
+ var registered3 = false;
13054
13299
  function registerBuiltins() {
13055
- if (registered2) return;
13056
- registered2 = true;
13300
+ if (registered3) return;
13301
+ registered3 = true;
13057
13302
  registerProvider(ANTHROPIC);
13058
13303
  registerProvider(OPENAI);
13059
13304
  registerProvider(OPENROUTER);
@@ -13282,7 +13527,9 @@ function toAnthropicWireMessage(message) {
13282
13527
  return {
13283
13528
  type: "tool_result",
13284
13529
  tool_use_id: part.toolUseId,
13285
- content: part.content,
13530
+ // SE7 — this wire is block-capable: strings pass through, structured
13531
+ // text/image blocks are forwarded natively.
13532
+ content: toBlockToolResultContent(part.content),
13286
13533
  ...part.isError === true ? { is_error: true } : {}
13287
13534
  };
13288
13535
  });
@@ -14074,7 +14321,8 @@ function toOllamaMessages(message) {
14074
14321
  if (part.type === "tool_result") {
14075
14322
  out.push({
14076
14323
  role: "tool",
14077
- content: part.content,
14324
+ // SE7 — string-only tool role: text blocks flatten; image fails fast.
14325
+ content: toStringToolResultContent(part.content, "ollama"),
14078
14326
  tool_name: part.toolUseId
14079
14327
  });
14080
14328
  }
@@ -14611,7 +14859,9 @@ function userOrToolMessages(message) {
14611
14859
  out.push({
14612
14860
  role: "tool",
14613
14861
  tool_call_id: part.toolUseId,
14614
- content: part.content
14862
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
14863
+ // image block fails fast (ConfigurationError).
14864
+ content: toStringToolResultContent(part.content, "openai")
14615
14865
  });
14616
14866
  }
14617
14867
  }
@@ -15541,18 +15791,20 @@ function levenshtein(a, b) {
15541
15791
  function createRealLocalRun(options) {
15542
15792
  const { userText, id, startTime } = prepareRunContext(options.message);
15543
15793
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
15544
- const unusedFixtureScript = {
15794
+ const runScript = {
15545
15795
  events: [],
15546
15796
  finalStatus: "running",
15547
15797
  cancellable: false,
15548
- conversation: []
15798
+ conversation: [],
15799
+ // SE3 — carry the turn's provenance so buildResult forwards it onto RunResult.origin.
15800
+ ...options.sendOptions.origin !== void 0 ? { origin: options.sendOptions.origin } : {}
15549
15801
  };
15550
15802
  const handle = new RealLocalRun(
15551
15803
  {
15552
15804
  id,
15553
15805
  agentId: options.agentId,
15554
15806
  model: options.model,
15555
- script: unusedFixtureScript,
15807
+ script: runScript,
15556
15808
  supportedOps: supported,
15557
15809
  startTime
15558
15810
  },
@@ -15664,6 +15916,8 @@ function buildLoopInputs(options, runId, userText) {
15664
15916
  // M7 — forward SendOptions.context to the loop so every tool handler receives
15665
15917
  // it on `ctx.context` (shared run config set once, e.g. projectRoot).
15666
15918
  ...options.sendOptions.context !== void 0 ? { context: options.sendOptions.context } : {},
15919
+ // SE2 — forward the opt-in typed runtime-event sink to the loop.
15920
+ ...options.sendOptions.onRunEvent !== void 0 ? { runEventSink: options.sendOptions.onRunEvent } : {},
15667
15921
  // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
15668
15922
  // can enable them via SendOptions (not only internal AgentLoopInputs).
15669
15923
  ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
@@ -17408,7 +17662,7 @@ function wrapRunWithPostReplyHook(args) {
17408
17662
  async function executeSendLocked(inputs, message, options) {
17409
17663
  if (inputs.disposed) throw new exports.AgentDisposedError(inputs.agentId);
17410
17664
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
17411
- inputs.applyModelOverride(options.model);
17665
+ inputs.applyModelOverride(normalizeModel(options.model));
17412
17666
  const userText = typeof message === "string" ? message : message.text;
17413
17667
  if (inputs.options.onBeforeSend !== void 0) {
17414
17668
  await inputs.options.onBeforeSend({
@@ -17560,7 +17814,7 @@ var LocalAgent = class {
17560
17814
  constructor(options) {
17561
17815
  this.agentId = options.agentId ?? generateLocalAgentId();
17562
17816
  this._telemetry = createTelemetry(options.telemetry);
17563
- this.model = options.model;
17817
+ this.model = normalizeModel(options.model);
17564
17818
  this.options = options;
17565
17819
  this.workspaceCwd = resolveCwd(options.local?.cwd);
17566
17820
  this.conversationStorage = options.conversationStorage;
@@ -17627,6 +17881,11 @@ var LocalAgent = class {
17627
17881
  hooks() {
17628
17882
  return this.hooksExecutor;
17629
17883
  }
17884
+ // SE9 — integrated structured output; delegates to the shared helper.
17885
+ generate(message, options) {
17886
+ const { apiKey, local } = this.options;
17887
+ return agentGenerate(this, this.model, apiKey, local, message, options);
17888
+ }
17630
17889
  async send(message, options = {}) {
17631
17890
  if (options.tools !== void 0 && options.tools.length > 0) {
17632
17891
  validateToolCatalog(options.tools);
@@ -17866,6 +18125,7 @@ function includesSetting(options, source) {
17866
18125
 
17867
18126
  // src/agent-helpers.ts
17868
18127
  async function runCreateUnderSpan(options, span) {
18128
+ options = { ...options, model: normalizeModel(options.model) };
17869
18129
  validateAgentOptions(options);
17870
18130
  validateCloudToolParity(options);
17871
18131
  await guardAgainstIdCollision(options);
@@ -17939,7 +18199,10 @@ async function createLocalAgent(options) {
17939
18199
  const willFlowToProvider = !isFixtureApiKey(apiKey) && !shouldUseRealLocalRuntime(apiKey);
17940
18200
  const shape = validateApiKeyShape(apiKey, {
17941
18201
  strict: willFlowToProvider,
17942
- ...willFlowToProvider ? { provider: providerFromModelId(options.model?.id) } : {}
18202
+ // `options.model` is already normalized by `runCreateUnderSpan`; `normalizeModel`
18203
+ // here is the idempotent narrowing of the widened public type (`{id}` passes
18204
+ // through by reference) — cleaner than an `as` cast.
18205
+ ...willFlowToProvider ? { provider: providerFromModelId(normalizeModel(options.model)?.id) } : {}
17943
18206
  });
17944
18207
  if (shape.malformed) {
17945
18208
  throw new exports.AuthenticationError(shape.message, { code: "malformed_api_key" });
@@ -18005,6 +18268,10 @@ async function rehydrateExistingAgent(agentId, existing, options) {
18005
18268
  ...existing.options,
18006
18269
  ...options,
18007
18270
  ...mergedLocal !== void 0 ? { local: mergedLocal } : {},
18271
+ // SE8 — normalize a caller-supplied bare-string model override at this resume
18272
+ // boundary (Agent.resume never flows through runCreateUnderSpan). Cloud resume
18273
+ // honors it; local resume forces the persisted model below.
18274
+ model: normalizeModel(options.model ?? existing.options.model),
18008
18275
  mcpServers: void 0,
18009
18276
  agentId
18010
18277
  };
@@ -18371,6 +18638,7 @@ async function getOrCreateUncached(agentId, options) {
18371
18638
  }
18372
18639
  setAgentFacade({
18373
18640
  create: (options) => Agent.create(options),
18641
+ delete: (agentId) => Agent.delete(agentId),
18374
18642
  prompt: (message, options) => Agent.prompt(message, options),
18375
18643
  get: (agentId) => Agent.get(agentId),
18376
18644
  resume: (agentId, options) => Agent.resume(agentId, options),
@@ -19331,6 +19599,8 @@ init_generate_object();
19331
19599
  // src/internal/persistence/conversation-storage-memory.ts
19332
19600
  var InMemoryConversationStorage = class {
19333
19601
  #store = /* @__PURE__ */ new Map();
19602
+ // SE4 — session-level metadata (title/tag), kept beside the transcript.
19603
+ #meta = /* @__PURE__ */ new Map();
19334
19604
  async getMessages(conversationId, opts) {
19335
19605
  const existing = this.#store.get(conversationId);
19336
19606
  return existing === void 0 ? [] : paginate(existing.slice(), opts);
@@ -19359,15 +19629,20 @@ var InMemoryConversationStorage = class {
19359
19629
  }
19360
19630
  async deleteConversation(conversationId) {
19361
19631
  this.#store.delete(conversationId);
19632
+ this.#meta.delete(conversationId);
19362
19633
  }
19363
19634
  async deleteScope(prefix) {
19364
19635
  let n = 0;
19365
19636
  for (const id of [...this.#store.keys()]) {
19366
19637
  if (id.startsWith(prefix)) {
19367
19638
  this.#store.delete(id);
19639
+ this.#meta.delete(id);
19368
19640
  n += 1;
19369
19641
  }
19370
19642
  }
19643
+ for (const id of [...this.#meta.keys()]) {
19644
+ if (id.startsWith(prefix)) this.#meta.delete(id);
19645
+ }
19371
19646
  return n;
19372
19647
  }
19373
19648
  async listConversationIds(opts) {
@@ -19375,8 +19650,17 @@ var InMemoryConversationStorage = class {
19375
19650
  if (opts?.limit !== void 0) return all.slice(0, opts.limit);
19376
19651
  return all;
19377
19652
  }
19653
+ async getSessionMeta(conversationId) {
19654
+ const meta = this.#meta.get(conversationId);
19655
+ return meta === void 0 ? void 0 : { ...meta };
19656
+ }
19657
+ async setSessionMeta(conversationId, patch) {
19658
+ const current = this.#meta.get(conversationId) ?? {};
19659
+ this.#meta.set(conversationId, applyMetaPatch(current, patch));
19660
+ }
19378
19661
  async dispose() {
19379
19662
  this.#store.clear();
19663
+ this.#meta.clear();
19380
19664
  }
19381
19665
  };
19382
19666
 
@@ -20116,6 +20400,21 @@ async function migrateSqliteToLance2(options) {
20116
20400
  }
20117
20401
 
20118
20402
  // src/permission-engine.ts
20403
+ function applyMode(verdict, mode, explicit) {
20404
+ if (verdict === "deny") return "deny";
20405
+ switch (mode) {
20406
+ case "default":
20407
+ return verdict;
20408
+ case "plan":
20409
+ return verdict === "allow" ? "allow" : "deny";
20410
+ case "acceptEdits":
20411
+ if (verdict === "ask") return explicit ? "ask" : "allow";
20412
+ return verdict;
20413
+ // allow stays allow
20414
+ case "bypass":
20415
+ return "allow";
20416
+ }
20417
+ }
20119
20418
  function argMatches(matcher, value) {
20120
20419
  if (typeof matcher === "function") return matcher(value);
20121
20420
  if (value === void 0) return false;
@@ -20136,14 +20435,14 @@ var PermissionEngine = class {
20136
20435
  * argument values, so the same tool name can resolve to different actions
20137
20436
  * depending on what it is asked to do.
20138
20437
  */
20139
- evaluate(toolName, args) {
20438
+ evaluate(toolName, args, mode = "default") {
20140
20439
  for (const rule of this.rules) {
20141
20440
  const nameMatches = typeof rule.tool === "string" ? rule.tool === toolName : rule.tool.test(toolName);
20142
20441
  if (!nameMatches) continue;
20143
20442
  if (rule.args !== void 0 && !this.#argsMatch(rule.args, args)) continue;
20144
- return rule.action;
20443
+ return applyMode(rule.action, mode, true);
20145
20444
  }
20146
- return this.defaultAction;
20445
+ return applyMode(this.defaultAction, mode, false);
20147
20446
  }
20148
20447
  #argsMatch(matchers, args) {
20149
20448
  const call = args ?? {};
@@ -20155,21 +20454,32 @@ var PermissionEngine = class {
20155
20454
  };
20156
20455
 
20157
20456
  // src/permission-plugin.ts
20457
+ async function resolveAsk(opts, name, args, mode) {
20458
+ if (opts.canUseTool !== void 0) {
20459
+ let decision;
20460
+ try {
20461
+ decision = await opts.canUseTool(name, args, { toolName: name, mode });
20462
+ } catch {
20463
+ return { block: true, message: `permission gate error (fail-closed): ${name}` };
20464
+ }
20465
+ return decision.behavior === "deny" ? { block: true, message: decision.message ?? `denied: ${name}` } : void 0;
20466
+ }
20467
+ return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20468
+ }
20158
20469
  function createPermissionPlugin(engine, opts = {}) {
20470
+ const mode = opts.mode ?? "default";
20159
20471
  return definePlugin({
20160
20472
  name: opts.name ?? "permission-engine",
20161
20473
  version: "1.0.0",
20162
20474
  kind: "general",
20163
20475
  register(ctx) {
20164
- ctx.on("pre_tool_call", (rawCtx) => {
20476
+ ctx.on("pre_tool_call", async (rawCtx) => {
20165
20477
  const { name, args } = rawCtx;
20166
- const action = engine.evaluate(name, args);
20478
+ const action = engine.evaluate(name, args, mode);
20167
20479
  if (action === "deny") {
20168
20480
  return { block: true, message: `denied by permission engine: ${name}` };
20169
20481
  }
20170
- if (action === "ask") {
20171
- return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20172
- }
20482
+ if (action === "ask") return resolveAsk(opts, name, args, mode);
20173
20483
  return void 0;
20174
20484
  });
20175
20485
  }
@@ -20275,6 +20585,96 @@ var Security = class {
20275
20585
  }
20276
20586
  };
20277
20587
 
20588
+ // src/session-manager.ts
20589
+ var SUMMARY_PREVIEW_MAX = 80;
20590
+ function createSessionManager(storage2) {
20591
+ return {
20592
+ async listSessions(opts) {
20593
+ if (typeof storage2.listConversationIds !== "function") {
20594
+ return {
20595
+ supported: false,
20596
+ reason: "storage adapter does not support listing conversations (listConversationIds)"
20597
+ };
20598
+ }
20599
+ const ids = await storage2.listConversationIds();
20600
+ if (ids === void 0) {
20601
+ return {
20602
+ supported: false,
20603
+ reason: "storage adapter reported listing as unsupported (listConversationIds \u2192 undefined)"
20604
+ };
20605
+ }
20606
+ const windowed = windowIds(ids, opts);
20607
+ const summaries = [];
20608
+ for (const id of windowed) {
20609
+ summaries.push(await buildSummary(storage2, id));
20610
+ }
20611
+ return { supported: true, value: summaries };
20612
+ },
20613
+ getSessionMessages(id, opts) {
20614
+ return storage2.getMessages(id, opts);
20615
+ },
20616
+ async renameSession(id, title) {
20617
+ if (typeof storage2.setSessionMeta !== "function") {
20618
+ return unsupportedWrite();
20619
+ }
20620
+ await storage2.setSessionMeta(id, { title });
20621
+ return { supported: true, value: void 0 };
20622
+ },
20623
+ async tagSession(id, tag) {
20624
+ if (typeof storage2.setSessionMeta !== "function") {
20625
+ return unsupportedWrite();
20626
+ }
20627
+ await storage2.setSessionMeta(id, { tag });
20628
+ return { supported: true, value: void 0 };
20629
+ }
20630
+ };
20631
+ }
20632
+ function unsupportedWrite() {
20633
+ return {
20634
+ supported: false,
20635
+ reason: "storage adapter does not support writing session metadata (setSessionMeta)"
20636
+ };
20637
+ }
20638
+ function windowIds(ids, opts) {
20639
+ const start = opts?.offset !== void 0 && opts.offset > 0 ? opts.offset : 0;
20640
+ const rawLimit = opts?.limit;
20641
+ if (rawLimit !== void 0 && rawLimit <= 0) return [];
20642
+ const end = rawLimit !== void 0 ? start + rawLimit : void 0;
20643
+ return ids.slice(start, end);
20644
+ }
20645
+ async function buildSummary(storage2, id) {
20646
+ const messages = await storage2.getMessages(id);
20647
+ const firstUser = messages.find((m) => m.role === "user")?.content;
20648
+ const firstPrompt = firstUser !== void 0 && firstUser.length > 0 ? firstUser : void 0;
20649
+ const lastModified = deriveLastModified(messages);
20650
+ const meta = typeof storage2.getSessionMeta === "function" ? await storage2.getSessionMeta(id) : void 0;
20651
+ const title = meta?.title;
20652
+ const tag = meta?.tag;
20653
+ const summary = title ?? previewOf(firstPrompt);
20654
+ return {
20655
+ id,
20656
+ messageCount: messages.length,
20657
+ ...firstPrompt !== void 0 ? { firstPrompt } : {},
20658
+ ...lastModified !== void 0 ? { lastModified } : {},
20659
+ ...title !== void 0 ? { title } : {},
20660
+ ...tag !== void 0 ? { tag } : {},
20661
+ ...summary !== void 0 ? { summary } : {}
20662
+ };
20663
+ }
20664
+ function deriveLastModified(messages) {
20665
+ let last;
20666
+ for (const m of messages) {
20667
+ if (m.at !== void 0 && (last === void 0 || m.at > last)) last = m.at;
20668
+ }
20669
+ return last;
20670
+ }
20671
+ function previewOf(text) {
20672
+ if (text === void 0) return void 0;
20673
+ const oneLine = text.replace(/\s+/g, " ").trim();
20674
+ if (oneLine.length === 0) return void 0;
20675
+ return oneLine.length > SUMMARY_PREVIEW_MAX ? `${oneLine.slice(0, SUMMARY_PREVIEW_MAX - 1)}\u2026` : oneLine;
20676
+ }
20677
+
20278
20678
  // src/session-scope.ts
20279
20679
  function scopedConversationId(scope, id) {
20280
20680
  return `${scope}__${id}`;
@@ -20295,7 +20695,7 @@ var PersistenceSchema = zod.z.object({
20295
20695
  // src/workflow.ts
20296
20696
  init_path_guard();
20297
20697
  init_workflow();
20298
- zod.z.object({
20698
+ var RetryPolicySchema = zod.z.object({
20299
20699
  // EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
20300
20700
  maxAttempts: zod.z.number().int("retry.maxAttempts must be integer").min(1, "retry.maxAttempts must be >= 1").max(20, "retry.maxAttempts must be <= 20"),
20301
20701
  initialBackoffMs: zod.z.number().int().min(0).optional(),
@@ -20493,12 +20893,15 @@ var Workflow = class {
20493
20893
  };
20494
20894
  function agentStep(id, agent, promptTemplate, opts) {
20495
20895
  validateStepId(id);
20896
+ if (opts?.retry !== void 0) RetryPolicySchema.parse(opts.retry);
20496
20897
  return {
20497
20898
  kind: "agent",
20498
20899
  id,
20499
20900
  agent,
20500
20901
  promptTemplate,
20501
- ...{}
20902
+ ...opts?.retry !== void 0 ? { retry: opts.retry } : {},
20903
+ // SE3 — carry the turn's provenance down to `agent.send()` (metadata-only).
20904
+ ...opts?.origin !== void 0 ? { origin: opts.origin } : {}
20502
20905
  };
20503
20906
  }
20504
20907
  function validateStepId(id) {
@@ -20546,7 +20949,8 @@ function createSquad(options) {
20546
20949
  for (let i = 0; i < agents2.length; i++) {
20547
20950
  const agent = agents2[i];
20548
20951
  if (agent === void 0) continue;
20549
- builder = builder.then(agentStep(`agent-${i}`, agent, (prev) => String(prev)));
20952
+ const opts = i > 0 ? { origin: { kind: "peer", from: `agent-${i - 1}` } } : void 0;
20953
+ builder = builder.then(agentStep(`agent-${i}`, agent, (prev) => String(prev), opts));
20550
20954
  }
20551
20955
  const run = await builder.commit().run(input);
20552
20956
  return { result: run.output, status: run.status, steps: run.stepResults };
@@ -21013,7 +21417,9 @@ exports.PermissionEngine = PermissionEngine;
21013
21417
  exports.Security = Security;
21014
21418
  exports.Task = Task;
21015
21419
  exports.Theokit = Theokit;
21420
+ exports.ToolError = ToolError;
21016
21421
  exports.UsageAccumulator = UsageAccumulator;
21422
+ exports.applyMode = applyMode;
21017
21423
  exports.buildReplayHistory = buildReplayHistory;
21018
21424
  exports.chargeAndCheckThresholds = chargeAndCheckThresholds;
21019
21425
  exports.computeCost = computeCost;
@@ -21021,11 +21427,13 @@ exports.createAgentFactory = createAgentFactory;
21021
21427
  exports.createCounterBudgetTracker = createCounterBudgetTracker;
21022
21428
  exports.createNoopMemoryProvider = createNoopMemoryProvider;
21023
21429
  exports.createPermissionPlugin = createPermissionPlugin;
21430
+ exports.createSessionManager = createSessionManager;
21024
21431
  exports.createSkill = createSkill;
21025
21432
  exports.createSquad = createSquad;
21026
21433
  exports.definePlugin = definePlugin;
21027
21434
  exports.defineProvider = defineProvider;
21028
21435
  exports.defineTool = defineTool;
21436
+ exports.emitRunEvent = emitRunEvent;
21029
21437
  exports.extractRawId = extractRawId;
21030
21438
  exports.getPricingEntry = getPricingEntry;
21031
21439
  exports.inferApiMode = inferApiMode;