@theokit/sdk 2.20.0 → 2.21.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 (88) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/a2a/index.cjs +592 -290
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +593 -291
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/a2a/types.d.cts +7 -0
  7. package/dist/a2a/types.d.ts +7 -0
  8. package/dist/agent-builder.d.ts +2 -1
  9. package/dist/agent-generate.d.ts +12 -0
  10. package/dist/client/index.cjs.map +1 -1
  11. package/dist/client/index.d.cts +5 -0
  12. package/dist/client/index.d.ts +5 -0
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/client/theokit-client.d.cts +6 -0
  15. package/dist/client/theokit-client.d.ts +6 -0
  16. package/dist/client/types.d.cts +2 -0
  17. package/dist/client/types.d.ts +2 -0
  18. package/dist/{cron-D2yLOrk2.d.ts → cron-YrmsszEN.d.cts} +53 -3
  19. package/dist/{cron-B8fqui49.d.cts → cron-dpvtRoro.d.ts} +53 -3
  20. package/dist/cron.cjs +642 -387
  21. package/dist/cron.cjs.map +1 -1
  22. package/dist/cron.d.cts +3 -2
  23. package/dist/cron.d.ts +3 -2
  24. package/dist/cron.js +643 -388
  25. package/dist/cron.js.map +1 -1
  26. package/dist/{errors-5lj1EWgs.d.ts → errors-C4vZPqXf.d.ts} +2 -2
  27. package/dist/{errors-CE-lMBi2.d.cts → errors-DrcpYVfZ.d.cts} +2 -2
  28. package/dist/errors.d.cts +3 -2
  29. package/dist/eval.cjs +642 -387
  30. package/dist/eval.cjs.map +1 -1
  31. package/dist/eval.js +642 -387
  32. package/dist/eval.js.map +1 -1
  33. package/dist/generate-object.d.ts +4 -3
  34. package/dist/index.cjs +788 -390
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +259 -17
  37. package/dist/index.d.ts +259 -17
  38. package/dist/index.js +786 -392
  39. package/dist/index.js.map +1 -1
  40. package/dist/internal/agent-loop/loop-types.d.ts +2 -0
  41. package/dist/internal/agent-loop/tool-result-guard.d.ts +1 -0
  42. package/dist/internal/llm/tool-result-content.d.ts +40 -0
  43. package/dist/internal/llm/types.d.ts +6 -1
  44. package/dist/internal/persistence/conversation-storage-fs.d.cts +3 -1
  45. package/dist/internal/persistence/conversation-storage-fs.d.ts +3 -1
  46. package/dist/internal/persistence/conversation-storage-memory.d.cts +3 -1
  47. package/dist/internal/persistence/conversation-storage-memory.d.ts +3 -1
  48. package/dist/internal/persistence/session-meta.d.cts +13 -0
  49. package/dist/internal/persistence/session-meta.d.ts +13 -0
  50. package/dist/internal/runtime/model-selection.d.ts +14 -0
  51. package/dist/internal/structured-output-helpers.d.ts +1 -1
  52. package/dist/permission-engine.d.ts +32 -1
  53. package/dist/{run-BgfBWX-z.d.cts → run-BMo8yRwK.d.cts} +262 -19
  54. package/dist/{run-BgfBWX-z.d.ts → run-BMo8yRwK.d.ts} +262 -19
  55. package/dist/stream-object.d.ts +2 -1
  56. package/dist/tool-error.d.ts +30 -0
  57. package/dist/types/agent-prims.d.ts +10 -8
  58. package/dist/types/agent.d.ts +12 -1
  59. package/dist/types/content-blocks.d.ts +47 -0
  60. package/dist/types/conversation-storage.d.ts +38 -0
  61. package/dist/types/index.d.ts +1 -0
  62. package/dist/types/messages.d.ts +2 -9
  63. package/dist/types/run-events.d.ts +84 -0
  64. package/dist/types/run.d.ts +115 -1
  65. package/dist/types/session.d.ts +99 -0
  66. package/dist/types/workflow.d.ts +7 -0
  67. package/dist/workflow.cjs +7 -2
  68. package/dist/workflow.cjs.map +1 -1
  69. package/dist/workflow.d.cts +2 -0
  70. package/dist/workflow.d.ts +2 -0
  71. package/dist/workflow.js +7 -2
  72. package/dist/workflow.js.map +1 -1
  73. package/package.json +14 -34
  74. package/dist/internal/observability/context.d.cts +0 -23
  75. package/dist/internal/observability/context.d.ts +0 -23
  76. package/dist/internal/observability/index.cjs +0 -38
  77. package/dist/internal/observability/index.cjs.map +0 -1
  78. package/dist/internal/observability/index.d.cts +0 -8
  79. package/dist/internal/observability/index.d.ts +0 -8
  80. package/dist/internal/observability/index.js +0 -33
  81. package/dist/internal/observability/index.js.map +0 -1
  82. package/dist/internal/plugins/index.cjs +0 -363
  83. package/dist/internal/plugins/index.cjs.map +0 -1
  84. package/dist/internal/plugins/index.js +0 -357
  85. package/dist/internal/plugins/index.js.map +0 -1
  86. package/dist/internal/workflow/index.d.ts +0 -12
  87. package/dist/server/adapter/index.d.cts +0 -8
  88. 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
  }
@@ -3611,334 +3838,107 @@ async function submit(internal) {
3611
3838
  state.aborters.set(resolvedId, aborter);
3612
3839
  if (internal.signal !== void 0) {
3613
3840
  internal.signal.addEventListener("abort", () => aborter.abort(internal.signal?.reason), {
3614
- once: true
3615
- });
3616
- }
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
- };
3841
+ once: true
3842
+ });
3843
+ }
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)) {
@@ -11762,9 +11933,13 @@ async function runHandlerTool(kind, handler, call, signal, context) {
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 });
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
 
@@ -13050,10 +13285,10 @@ function stripVertexPrefix(modelId) {
13050
13285
  }
13051
13286
 
13052
13287
  // src/internal/providers/builtin/index.ts
13053
- var registered2 = false;
13288
+ var registered3 = false;
13054
13289
  function registerBuiltins() {
13055
- if (registered2) return;
13056
- registered2 = true;
13290
+ if (registered3) return;
13291
+ registered3 = true;
13057
13292
  registerProvider(ANTHROPIC);
13058
13293
  registerProvider(OPENAI);
13059
13294
  registerProvider(OPENROUTER);
@@ -13282,7 +13517,9 @@ function toAnthropicWireMessage(message) {
13282
13517
  return {
13283
13518
  type: "tool_result",
13284
13519
  tool_use_id: part.toolUseId,
13285
- content: part.content,
13520
+ // SE7 — this wire is block-capable: strings pass through, structured
13521
+ // text/image blocks are forwarded natively.
13522
+ content: toBlockToolResultContent(part.content),
13286
13523
  ...part.isError === true ? { is_error: true } : {}
13287
13524
  };
13288
13525
  });
@@ -14074,7 +14311,8 @@ function toOllamaMessages(message) {
14074
14311
  if (part.type === "tool_result") {
14075
14312
  out.push({
14076
14313
  role: "tool",
14077
- content: part.content,
14314
+ // SE7 — string-only tool role: text blocks flatten; image fails fast.
14315
+ content: toStringToolResultContent(part.content, "ollama"),
14078
14316
  tool_name: part.toolUseId
14079
14317
  });
14080
14318
  }
@@ -14611,7 +14849,9 @@ function userOrToolMessages(message) {
14611
14849
  out.push({
14612
14850
  role: "tool",
14613
14851
  tool_call_id: part.toolUseId,
14614
- content: part.content
14852
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
14853
+ // image block fails fast (ConfigurationError).
14854
+ content: toStringToolResultContent(part.content, "openai")
14615
14855
  });
14616
14856
  }
14617
14857
  }
@@ -15541,18 +15781,20 @@ function levenshtein(a, b) {
15541
15781
  function createRealLocalRun(options) {
15542
15782
  const { userText, id, startTime } = prepareRunContext(options.message);
15543
15783
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
15544
- const unusedFixtureScript = {
15784
+ const runScript = {
15545
15785
  events: [],
15546
15786
  finalStatus: "running",
15547
15787
  cancellable: false,
15548
- conversation: []
15788
+ conversation: [],
15789
+ // SE3 — carry the turn's provenance so buildResult forwards it onto RunResult.origin.
15790
+ ...options.sendOptions.origin !== void 0 ? { origin: options.sendOptions.origin } : {}
15549
15791
  };
15550
15792
  const handle = new RealLocalRun(
15551
15793
  {
15552
15794
  id,
15553
15795
  agentId: options.agentId,
15554
15796
  model: options.model,
15555
- script: unusedFixtureScript,
15797
+ script: runScript,
15556
15798
  supportedOps: supported,
15557
15799
  startTime
15558
15800
  },
@@ -15664,6 +15906,8 @@ function buildLoopInputs(options, runId, userText) {
15664
15906
  // M7 — forward SendOptions.context to the loop so every tool handler receives
15665
15907
  // it on `ctx.context` (shared run config set once, e.g. projectRoot).
15666
15908
  ...options.sendOptions.context !== void 0 ? { context: options.sendOptions.context } : {},
15909
+ // SE2 — forward the opt-in typed runtime-event sink to the loop.
15910
+ ...options.sendOptions.onRunEvent !== void 0 ? { runEventSink: options.sendOptions.onRunEvent } : {},
15667
15911
  // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
15668
15912
  // can enable them via SendOptions (not only internal AgentLoopInputs).
15669
15913
  ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
@@ -17408,7 +17652,7 @@ function wrapRunWithPostReplyHook(args) {
17408
17652
  async function executeSendLocked(inputs, message, options) {
17409
17653
  if (inputs.disposed) throw new exports.AgentDisposedError(inputs.agentId);
17410
17654
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
17411
- inputs.applyModelOverride(options.model);
17655
+ inputs.applyModelOverride(normalizeModel(options.model));
17412
17656
  const userText = typeof message === "string" ? message : message.text;
17413
17657
  if (inputs.options.onBeforeSend !== void 0) {
17414
17658
  await inputs.options.onBeforeSend({
@@ -17560,7 +17804,7 @@ var LocalAgent = class {
17560
17804
  constructor(options) {
17561
17805
  this.agentId = options.agentId ?? generateLocalAgentId();
17562
17806
  this._telemetry = createTelemetry(options.telemetry);
17563
- this.model = options.model;
17807
+ this.model = normalizeModel(options.model);
17564
17808
  this.options = options;
17565
17809
  this.workspaceCwd = resolveCwd(options.local?.cwd);
17566
17810
  this.conversationStorage = options.conversationStorage;
@@ -17627,6 +17871,11 @@ var LocalAgent = class {
17627
17871
  hooks() {
17628
17872
  return this.hooksExecutor;
17629
17873
  }
17874
+ // SE9 — integrated structured output; delegates to the shared helper.
17875
+ generate(message, options) {
17876
+ const { apiKey, local } = this.options;
17877
+ return agentGenerate(this, this.model, apiKey, local, message, options);
17878
+ }
17630
17879
  async send(message, options = {}) {
17631
17880
  if (options.tools !== void 0 && options.tools.length > 0) {
17632
17881
  validateToolCatalog(options.tools);
@@ -17866,6 +18115,7 @@ function includesSetting(options, source) {
17866
18115
 
17867
18116
  // src/agent-helpers.ts
17868
18117
  async function runCreateUnderSpan(options, span) {
18118
+ options = { ...options, model: normalizeModel(options.model) };
17869
18119
  validateAgentOptions(options);
17870
18120
  validateCloudToolParity(options);
17871
18121
  await guardAgainstIdCollision(options);
@@ -17939,7 +18189,10 @@ async function createLocalAgent(options) {
17939
18189
  const willFlowToProvider = !isFixtureApiKey(apiKey) && !shouldUseRealLocalRuntime(apiKey);
17940
18190
  const shape = validateApiKeyShape(apiKey, {
17941
18191
  strict: willFlowToProvider,
17942
- ...willFlowToProvider ? { provider: providerFromModelId(options.model?.id) } : {}
18192
+ // `options.model` is already normalized by `runCreateUnderSpan`; `normalizeModel`
18193
+ // here is the idempotent narrowing of the widened public type (`{id}` passes
18194
+ // through by reference) — cleaner than an `as` cast.
18195
+ ...willFlowToProvider ? { provider: providerFromModelId(normalizeModel(options.model)?.id) } : {}
17943
18196
  });
17944
18197
  if (shape.malformed) {
17945
18198
  throw new exports.AuthenticationError(shape.message, { code: "malformed_api_key" });
@@ -18005,6 +18258,10 @@ async function rehydrateExistingAgent(agentId, existing, options) {
18005
18258
  ...existing.options,
18006
18259
  ...options,
18007
18260
  ...mergedLocal !== void 0 ? { local: mergedLocal } : {},
18261
+ // SE8 — normalize a caller-supplied bare-string model override at this resume
18262
+ // boundary (Agent.resume never flows through runCreateUnderSpan). Cloud resume
18263
+ // honors it; local resume forces the persisted model below.
18264
+ model: normalizeModel(options.model ?? existing.options.model),
18008
18265
  mcpServers: void 0,
18009
18266
  agentId
18010
18267
  };
@@ -18371,6 +18628,7 @@ async function getOrCreateUncached(agentId, options) {
18371
18628
  }
18372
18629
  setAgentFacade({
18373
18630
  create: (options) => Agent.create(options),
18631
+ delete: (agentId) => Agent.delete(agentId),
18374
18632
  prompt: (message, options) => Agent.prompt(message, options),
18375
18633
  get: (agentId) => Agent.get(agentId),
18376
18634
  resume: (agentId, options) => Agent.resume(agentId, options),
@@ -19331,6 +19589,8 @@ init_generate_object();
19331
19589
  // src/internal/persistence/conversation-storage-memory.ts
19332
19590
  var InMemoryConversationStorage = class {
19333
19591
  #store = /* @__PURE__ */ new Map();
19592
+ // SE4 — session-level metadata (title/tag), kept beside the transcript.
19593
+ #meta = /* @__PURE__ */ new Map();
19334
19594
  async getMessages(conversationId, opts) {
19335
19595
  const existing = this.#store.get(conversationId);
19336
19596
  return existing === void 0 ? [] : paginate(existing.slice(), opts);
@@ -19359,15 +19619,20 @@ var InMemoryConversationStorage = class {
19359
19619
  }
19360
19620
  async deleteConversation(conversationId) {
19361
19621
  this.#store.delete(conversationId);
19622
+ this.#meta.delete(conversationId);
19362
19623
  }
19363
19624
  async deleteScope(prefix) {
19364
19625
  let n = 0;
19365
19626
  for (const id of [...this.#store.keys()]) {
19366
19627
  if (id.startsWith(prefix)) {
19367
19628
  this.#store.delete(id);
19629
+ this.#meta.delete(id);
19368
19630
  n += 1;
19369
19631
  }
19370
19632
  }
19633
+ for (const id of [...this.#meta.keys()]) {
19634
+ if (id.startsWith(prefix)) this.#meta.delete(id);
19635
+ }
19371
19636
  return n;
19372
19637
  }
19373
19638
  async listConversationIds(opts) {
@@ -19375,8 +19640,17 @@ var InMemoryConversationStorage = class {
19375
19640
  if (opts?.limit !== void 0) return all.slice(0, opts.limit);
19376
19641
  return all;
19377
19642
  }
19643
+ async getSessionMeta(conversationId) {
19644
+ const meta = this.#meta.get(conversationId);
19645
+ return meta === void 0 ? void 0 : { ...meta };
19646
+ }
19647
+ async setSessionMeta(conversationId, patch) {
19648
+ const current = this.#meta.get(conversationId) ?? {};
19649
+ this.#meta.set(conversationId, applyMetaPatch(current, patch));
19650
+ }
19378
19651
  async dispose() {
19379
19652
  this.#store.clear();
19653
+ this.#meta.clear();
19380
19654
  }
19381
19655
  };
19382
19656
 
@@ -20116,6 +20390,21 @@ async function migrateSqliteToLance2(options) {
20116
20390
  }
20117
20391
 
20118
20392
  // src/permission-engine.ts
20393
+ function applyMode(verdict, mode, explicit) {
20394
+ if (verdict === "deny") return "deny";
20395
+ switch (mode) {
20396
+ case "default":
20397
+ return verdict;
20398
+ case "plan":
20399
+ return verdict === "allow" ? "allow" : "deny";
20400
+ case "acceptEdits":
20401
+ if (verdict === "ask") return explicit ? "ask" : "allow";
20402
+ return verdict;
20403
+ // allow stays allow
20404
+ case "bypass":
20405
+ return "allow";
20406
+ }
20407
+ }
20119
20408
  function argMatches(matcher, value) {
20120
20409
  if (typeof matcher === "function") return matcher(value);
20121
20410
  if (value === void 0) return false;
@@ -20136,14 +20425,14 @@ var PermissionEngine = class {
20136
20425
  * argument values, so the same tool name can resolve to different actions
20137
20426
  * depending on what it is asked to do.
20138
20427
  */
20139
- evaluate(toolName, args) {
20428
+ evaluate(toolName, args, mode = "default") {
20140
20429
  for (const rule of this.rules) {
20141
20430
  const nameMatches = typeof rule.tool === "string" ? rule.tool === toolName : rule.tool.test(toolName);
20142
20431
  if (!nameMatches) continue;
20143
20432
  if (rule.args !== void 0 && !this.#argsMatch(rule.args, args)) continue;
20144
- return rule.action;
20433
+ return applyMode(rule.action, mode, true);
20145
20434
  }
20146
- return this.defaultAction;
20435
+ return applyMode(this.defaultAction, mode, false);
20147
20436
  }
20148
20437
  #argsMatch(matchers, args) {
20149
20438
  const call = args ?? {};
@@ -20155,21 +20444,32 @@ var PermissionEngine = class {
20155
20444
  };
20156
20445
 
20157
20446
  // src/permission-plugin.ts
20447
+ async function resolveAsk(opts, name, args, mode) {
20448
+ if (opts.canUseTool !== void 0) {
20449
+ let decision;
20450
+ try {
20451
+ decision = await opts.canUseTool(name, args, { toolName: name, mode });
20452
+ } catch {
20453
+ return { block: true, message: `permission gate error (fail-closed): ${name}` };
20454
+ }
20455
+ return decision.behavior === "deny" ? { block: true, message: decision.message ?? `denied: ${name}` } : void 0;
20456
+ }
20457
+ return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20458
+ }
20158
20459
  function createPermissionPlugin(engine, opts = {}) {
20460
+ const mode = opts.mode ?? "default";
20159
20461
  return definePlugin({
20160
20462
  name: opts.name ?? "permission-engine",
20161
20463
  version: "1.0.0",
20162
20464
  kind: "general",
20163
20465
  register(ctx) {
20164
- ctx.on("pre_tool_call", (rawCtx) => {
20466
+ ctx.on("pre_tool_call", async (rawCtx) => {
20165
20467
  const { name, args } = rawCtx;
20166
- const action = engine.evaluate(name, args);
20468
+ const action = engine.evaluate(name, args, mode);
20167
20469
  if (action === "deny") {
20168
20470
  return { block: true, message: `denied by permission engine: ${name}` };
20169
20471
  }
20170
- if (action === "ask") {
20171
- return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20172
- }
20472
+ if (action === "ask") return resolveAsk(opts, name, args, mode);
20173
20473
  return void 0;
20174
20474
  });
20175
20475
  }
@@ -20275,6 +20575,96 @@ var Security = class {
20275
20575
  }
20276
20576
  };
20277
20577
 
20578
+ // src/session-manager.ts
20579
+ var SUMMARY_PREVIEW_MAX = 80;
20580
+ function createSessionManager(storage2) {
20581
+ return {
20582
+ async listSessions(opts) {
20583
+ if (typeof storage2.listConversationIds !== "function") {
20584
+ return {
20585
+ supported: false,
20586
+ reason: "storage adapter does not support listing conversations (listConversationIds)"
20587
+ };
20588
+ }
20589
+ const ids = await storage2.listConversationIds();
20590
+ if (ids === void 0) {
20591
+ return {
20592
+ supported: false,
20593
+ reason: "storage adapter reported listing as unsupported (listConversationIds \u2192 undefined)"
20594
+ };
20595
+ }
20596
+ const windowed = windowIds(ids, opts);
20597
+ const summaries = [];
20598
+ for (const id of windowed) {
20599
+ summaries.push(await buildSummary(storage2, id));
20600
+ }
20601
+ return { supported: true, value: summaries };
20602
+ },
20603
+ getSessionMessages(id, opts) {
20604
+ return storage2.getMessages(id, opts);
20605
+ },
20606
+ async renameSession(id, title) {
20607
+ if (typeof storage2.setSessionMeta !== "function") {
20608
+ return unsupportedWrite();
20609
+ }
20610
+ await storage2.setSessionMeta(id, { title });
20611
+ return { supported: true, value: void 0 };
20612
+ },
20613
+ async tagSession(id, tag) {
20614
+ if (typeof storage2.setSessionMeta !== "function") {
20615
+ return unsupportedWrite();
20616
+ }
20617
+ await storage2.setSessionMeta(id, { tag });
20618
+ return { supported: true, value: void 0 };
20619
+ }
20620
+ };
20621
+ }
20622
+ function unsupportedWrite() {
20623
+ return {
20624
+ supported: false,
20625
+ reason: "storage adapter does not support writing session metadata (setSessionMeta)"
20626
+ };
20627
+ }
20628
+ function windowIds(ids, opts) {
20629
+ const start = opts?.offset !== void 0 && opts.offset > 0 ? opts.offset : 0;
20630
+ const rawLimit = opts?.limit;
20631
+ if (rawLimit !== void 0 && rawLimit <= 0) return [];
20632
+ const end = rawLimit !== void 0 ? start + rawLimit : void 0;
20633
+ return ids.slice(start, end);
20634
+ }
20635
+ async function buildSummary(storage2, id) {
20636
+ const messages = await storage2.getMessages(id);
20637
+ const firstUser = messages.find((m) => m.role === "user")?.content;
20638
+ const firstPrompt = firstUser !== void 0 && firstUser.length > 0 ? firstUser : void 0;
20639
+ const lastModified = deriveLastModified(messages);
20640
+ const meta = typeof storage2.getSessionMeta === "function" ? await storage2.getSessionMeta(id) : void 0;
20641
+ const title = meta?.title;
20642
+ const tag = meta?.tag;
20643
+ const summary = title ?? previewOf(firstPrompt);
20644
+ return {
20645
+ id,
20646
+ messageCount: messages.length,
20647
+ ...firstPrompt !== void 0 ? { firstPrompt } : {},
20648
+ ...lastModified !== void 0 ? { lastModified } : {},
20649
+ ...title !== void 0 ? { title } : {},
20650
+ ...tag !== void 0 ? { tag } : {},
20651
+ ...summary !== void 0 ? { summary } : {}
20652
+ };
20653
+ }
20654
+ function deriveLastModified(messages) {
20655
+ let last;
20656
+ for (const m of messages) {
20657
+ if (m.at !== void 0 && (last === void 0 || m.at > last)) last = m.at;
20658
+ }
20659
+ return last;
20660
+ }
20661
+ function previewOf(text) {
20662
+ if (text === void 0) return void 0;
20663
+ const oneLine = text.replace(/\s+/g, " ").trim();
20664
+ if (oneLine.length === 0) return void 0;
20665
+ return oneLine.length > SUMMARY_PREVIEW_MAX ? `${oneLine.slice(0, SUMMARY_PREVIEW_MAX - 1)}\u2026` : oneLine;
20666
+ }
20667
+
20278
20668
  // src/session-scope.ts
20279
20669
  function scopedConversationId(scope, id) {
20280
20670
  return `${scope}__${id}`;
@@ -20295,7 +20685,7 @@ var PersistenceSchema = zod.z.object({
20295
20685
  // src/workflow.ts
20296
20686
  init_path_guard();
20297
20687
  init_workflow();
20298
- zod.z.object({
20688
+ var RetryPolicySchema = zod.z.object({
20299
20689
  // EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
20300
20690
  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
20691
  initialBackoffMs: zod.z.number().int().min(0).optional(),
@@ -20493,12 +20883,15 @@ var Workflow = class {
20493
20883
  };
20494
20884
  function agentStep(id, agent, promptTemplate, opts) {
20495
20885
  validateStepId(id);
20886
+ if (opts?.retry !== void 0) RetryPolicySchema.parse(opts.retry);
20496
20887
  return {
20497
20888
  kind: "agent",
20498
20889
  id,
20499
20890
  agent,
20500
20891
  promptTemplate,
20501
- ...{}
20892
+ ...opts?.retry !== void 0 ? { retry: opts.retry } : {},
20893
+ // SE3 — carry the turn's provenance down to `agent.send()` (metadata-only).
20894
+ ...opts?.origin !== void 0 ? { origin: opts.origin } : {}
20502
20895
  };
20503
20896
  }
20504
20897
  function validateStepId(id) {
@@ -20546,7 +20939,8 @@ function createSquad(options) {
20546
20939
  for (let i = 0; i < agents2.length; i++) {
20547
20940
  const agent = agents2[i];
20548
20941
  if (agent === void 0) continue;
20549
- builder = builder.then(agentStep(`agent-${i}`, agent, (prev) => String(prev)));
20942
+ const opts = i > 0 ? { origin: { kind: "peer", from: `agent-${i - 1}` } } : void 0;
20943
+ builder = builder.then(agentStep(`agent-${i}`, agent, (prev) => String(prev), opts));
20550
20944
  }
20551
20945
  const run = await builder.commit().run(input);
20552
20946
  return { result: run.output, status: run.status, steps: run.stepResults };
@@ -21013,7 +21407,9 @@ exports.PermissionEngine = PermissionEngine;
21013
21407
  exports.Security = Security;
21014
21408
  exports.Task = Task;
21015
21409
  exports.Theokit = Theokit;
21410
+ exports.ToolError = ToolError;
21016
21411
  exports.UsageAccumulator = UsageAccumulator;
21412
+ exports.applyMode = applyMode;
21017
21413
  exports.buildReplayHistory = buildReplayHistory;
21018
21414
  exports.chargeAndCheckThresholds = chargeAndCheckThresholds;
21019
21415
  exports.computeCost = computeCost;
@@ -21021,11 +21417,13 @@ exports.createAgentFactory = createAgentFactory;
21021
21417
  exports.createCounterBudgetTracker = createCounterBudgetTracker;
21022
21418
  exports.createNoopMemoryProvider = createNoopMemoryProvider;
21023
21419
  exports.createPermissionPlugin = createPermissionPlugin;
21420
+ exports.createSessionManager = createSessionManager;
21024
21421
  exports.createSkill = createSkill;
21025
21422
  exports.createSquad = createSquad;
21026
21423
  exports.definePlugin = definePlugin;
21027
21424
  exports.defineProvider = defineProvider;
21028
21425
  exports.defineTool = defineTool;
21426
+ exports.emitRunEvent = emitRunEvent;
21029
21427
  exports.extractRawId = extractRawId;
21030
21428
  exports.getPricingEntry = getPricingEntry;
21031
21429
  exports.inferApiMode = inferApiMode;