@theokit/sdk 2.19.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 (89) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/dist/a2a/index.cjs +611 -274
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +612 -275
  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/create-skill.d.ts +29 -0
  19. package/dist/{cron-D_wK1S-0.d.cts → cron-YrmsszEN.d.cts} +110 -3
  20. package/dist/{cron-Cep07kTz.d.ts → cron-dpvtRoro.d.ts} +110 -3
  21. package/dist/cron.cjs +660 -370
  22. package/dist/cron.cjs.map +1 -1
  23. package/dist/cron.d.cts +3 -2
  24. package/dist/cron.d.ts +3 -2
  25. package/dist/cron.js +661 -371
  26. package/dist/cron.js.map +1 -1
  27. package/dist/{errors-5lj1EWgs.d.ts → errors-C4vZPqXf.d.ts} +2 -2
  28. package/dist/{errors-CE-lMBi2.d.cts → errors-DrcpYVfZ.d.cts} +2 -2
  29. package/dist/errors.d.cts +3 -2
  30. package/dist/eval.cjs +660 -370
  31. package/dist/eval.cjs.map +1 -1
  32. package/dist/eval.js +660 -370
  33. package/dist/eval.js.map +1 -1
  34. package/dist/generate-object.d.ts +19 -4
  35. package/dist/index.cjs +867 -371
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +274 -16
  38. package/dist/index.d.ts +274 -16
  39. package/dist/index.js +863 -373
  40. package/dist/index.js.map +1 -1
  41. package/dist/internal/agent-loop/loop-types.d.ts +2 -0
  42. package/dist/internal/agent-loop/tool-result-guard.d.ts +1 -0
  43. package/dist/internal/llm/tool-result-content.d.ts +40 -0
  44. package/dist/internal/llm/types.d.ts +6 -1
  45. package/dist/internal/persistence/conversation-storage-fs.d.cts +3 -1
  46. package/dist/internal/persistence/conversation-storage-fs.d.ts +3 -1
  47. package/dist/internal/persistence/conversation-storage-memory.d.cts +3 -1
  48. package/dist/internal/persistence/conversation-storage-memory.d.ts +3 -1
  49. package/dist/internal/persistence/session-meta.d.cts +13 -0
  50. package/dist/internal/persistence/session-meta.d.ts +13 -0
  51. package/dist/internal/runtime/model-selection.d.ts +14 -0
  52. package/dist/internal/structured-output-helpers.d.ts +1 -1
  53. package/dist/permission-engine.d.ts +32 -1
  54. package/dist/{run-BgfBWX-z.d.cts → run-BMo8yRwK.d.cts} +262 -19
  55. package/dist/{run-BgfBWX-z.d.ts → run-BMo8yRwK.d.ts} +262 -19
  56. package/dist/stream-object.d.ts +2 -1
  57. package/dist/tool-error.d.ts +30 -0
  58. package/dist/types/agent-prims.d.ts +10 -8
  59. package/dist/types/agent.d.ts +22 -1
  60. package/dist/types/content-blocks.d.ts +47 -0
  61. package/dist/types/conversation-storage.d.ts +38 -0
  62. package/dist/types/index.d.ts +1 -0
  63. package/dist/types/messages.d.ts +2 -9
  64. package/dist/types/run-events.d.ts +84 -0
  65. package/dist/types/run.d.ts +115 -1
  66. package/dist/types/session.d.ts +99 -0
  67. package/dist/types/workflow.d.ts +7 -0
  68. package/dist/workflow.cjs +7 -2
  69. package/dist/workflow.cjs.map +1 -1
  70. package/dist/workflow.d.cts +2 -0
  71. package/dist/workflow.d.ts +2 -0
  72. package/dist/workflow.js +7 -2
  73. package/dist/workflow.js.map +1 -1
  74. package/package.json +3 -23
  75. package/dist/internal/observability/context.d.cts +0 -23
  76. package/dist/internal/observability/context.d.ts +0 -23
  77. package/dist/internal/observability/index.cjs +0 -38
  78. package/dist/internal/observability/index.cjs.map +0 -1
  79. package/dist/internal/observability/index.d.cts +0 -8
  80. package/dist/internal/observability/index.d.ts +0 -8
  81. package/dist/internal/observability/index.js +0 -33
  82. package/dist/internal/observability/index.js.map +0 -1
  83. package/dist/internal/plugins/index.cjs +0 -363
  84. package/dist/internal/plugins/index.cjs.map +0 -1
  85. package/dist/internal/plugins/index.js +0 -357
  86. package/dist/internal/plugins/index.js.map +0 -1
  87. package/dist/internal/workflow/index.d.ts +0 -12
  88. package/dist/server/adapter/index.d.cts +0 -8
  89. 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
  }
@@ -3615,309 +3842,103 @@ async function submit(internal) {
3615
3842
  });
3616
3843
  }
3617
3844
  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 generateObjectImpl(options, deps) {
3817
- const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
3818
- options.schema,
3819
- options.maxRetries
3820
- );
3821
- let capturedRaw;
3822
- let lastUsage = initialUsage;
3823
- const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
3824
- class CaptureSentinel extends Error {
3825
- constructor(captured) {
3826
- super("generate-object-capture");
3827
- this.captured = captured;
3828
- }
3829
- captured;
3830
- [sentinel] = true;
3831
- }
3832
- const outputTool = makeOutputTool(jsonSchema, (input) => {
3833
- if (capturedRaw === void 0) {
3834
- capturedRaw = input;
3835
- }
3836
- throw new CaptureSentinel(input);
3837
- });
3838
- const agentOptions = buildTransientAgentOptions({
3839
- model: options.model,
3840
- local: options.local,
3841
- outputTool,
3842
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
3843
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
3844
- ...options.providers !== void 0 ? { providers: options.providers } : {}
3845
- });
3846
- const agent = await deps.create(agentOptions);
3847
- try {
3848
- const userMessage = buildToolPrompt(options.prompt);
3849
- let lastParseError;
3850
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
3851
- capturedRaw = void 0;
3852
- const run = await agent.send(userMessage);
3853
- const result = await run.wait();
3854
- lastUsage = extractUsage2(result);
3855
- if (capturedRaw === void 0) {
3856
- if (result.status === "error" && result.error !== void 0) {
3857
- throw new exports.GenerateObjectError(
3858
- "no_tool_call",
3859
- `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
3860
- result.error
3861
- );
3862
- }
3863
- if (attempt === maxRetries) {
3864
- throw new exports.GenerateObjectError(
3865
- "no_tool_call",
3866
- "The model returned text instead of calling the `output` tool."
3867
- );
3868
- }
3869
- continue;
3870
- }
3871
- const parsed = options.schema.safeParse(capturedRaw);
3872
- if (parsed.success) {
3873
- return {
3874
- object: parsed.data,
3875
- raw: capturedRaw,
3876
- usage: lastUsage,
3877
- finishReason: "tool_use"
3878
- };
3879
- }
3880
- lastParseError = parsed.error;
3881
- }
3882
- if (options.errorStrategy === "return-raw") {
3883
- return {
3884
- object: capturedRaw,
3885
- raw: capturedRaw,
3886
- usage: lastUsage,
3887
- finishReason: "tool_use"
3888
- };
3889
- }
3890
- if (options.errorStrategy === "return-partial") {
3891
- return {
3892
- object: salvagePartial(options.schema, capturedRaw),
3893
- raw: capturedRaw,
3894
- usage: lastUsage,
3895
- finishReason: "tool_use"
3896
- };
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;
3853
+ }
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);
3897
3861
  }
3898
- throw new exports.GenerateObjectError(
3899
- "parse_failed",
3900
- "Schema parse failed after all retries.",
3901
- lastParseError
3902
- );
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);
3903
3886
  } finally {
3904
- await disposeAndDeleteTransient(agent, deps.delete);
3887
+ span.end();
3905
3888
  }
3906
3889
  }
3907
- exports.GenerateObjectError = void 0;
3908
- var init_generate_object = __esm({
3909
- "src/generate-object.ts"() {
3910
- init_structured_output_helpers();
3911
- exports.GenerateObjectError = class extends Error {
3912
- name = "GenerateObjectError";
3913
- code;
3914
- cause;
3915
- constructor(code, message, cause) {
3916
- super(message);
3917
- this.code = code;
3918
- 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);
3919
3940
  }
3920
- };
3941
+ });
3921
3942
  }
3922
3943
  });
3923
3944
 
@@ -3975,7 +3996,7 @@ async function* streamObjectImpl(options, deps) {
3975
3996
  }
3976
3997
  }
3977
3998
  const result = await run.wait();
3978
- lastUsage = extractUsage2(result);
3999
+ lastUsage = extractUsage(result);
3979
4000
  if (capturedRaw === void 0) {
3980
4001
  if (result.status === "error" && result.error !== void 0) {
3981
4002
  throw new exports.StreamObjectError(
@@ -4727,7 +4748,10 @@ async function runAgentStep(step, input, ctx) {
4727
4748
  };
4728
4749
  }
4729
4750
  const exec = async () => {
4730
- 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
+ );
4731
4755
  const result = await run.wait();
4732
4756
  if (result.status === "finished") {
4733
4757
  return result.result ?? "";
@@ -5499,6 +5523,7 @@ var AgentBuilder = class {
5499
5523
  constructor(deps) {
5500
5524
  this.deps = deps;
5501
5525
  }
5526
+ /** SE8 — accepts a bare-string id shorthand (`"openai/gpt-4o-mini"`) or a {@link ModelSelection}. */
5502
5527
  model(m) {
5503
5528
  this.opts.model = m;
5504
5529
  return this;
@@ -5856,13 +5881,87 @@ function isLocalAgentId(id) {
5856
5881
  return id.startsWith(PREFIX.localAgent);
5857
5882
  }
5858
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
+
5859
5947
  // src/internal/runtime/cloud/cloud-agent.ts
5860
5948
  init_errors();
5861
5949
  init_cwd_mutex();
5862
5950
  init_path_guard();
5863
5951
 
5864
- // src/internal/runtime/config/default-model.ts
5865
- 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
+ }
5866
5965
 
5867
5966
  // src/internal/runtime/registry/agent-registry-store.ts
5868
5967
  init_cwd_mutex();
@@ -5939,7 +6038,10 @@ var REGISTRY_RELATIVE_PATH = path.join(".theokit", "agents", "registry.json");
5939
6038
  function stripSecretsFromOptions(options) {
5940
6039
  return assignDefined({
5941
6040
  name: options.name,
5942
- 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
+ })(),
5943
6045
  systemPrompt: typeof options.systemPrompt === "string" ? options.systemPrompt : void 0,
5944
6046
  local: serializeLocal(options.local),
5945
6047
  cloud: serializeCloud(options.cloud),
@@ -6224,7 +6326,8 @@ function serializeCloudAgentConfig(options) {
6224
6326
  cloud: serializeCloud2(options.cloud)
6225
6327
  };
6226
6328
  if (typeof options.agentId === "string") payload.agentId = options.agentId;
6227
- 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 };
6228
6331
  if (typeof options.systemPrompt === "string") payload.systemPrompt = options.systemPrompt;
6229
6332
  const skills = serializeSkills(options.skills);
6230
6333
  if (skills !== void 0) payload.skills = skills;
@@ -7029,6 +7132,7 @@ function applyScriptMetrics(base, script) {
7029
7132
  if (script.cost !== void 0) base.cost = script.cost;
7030
7133
  if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
7031
7134
  if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
7135
+ if (script.origin !== void 0) base.origin = script.origin;
7032
7136
  }
7033
7137
 
7034
7138
  // src/internal/runtime/cloud/cloud-run.ts
@@ -7384,7 +7488,7 @@ var CloudAgent = class {
7384
7488
  disposed = false;
7385
7489
  constructor(options, providedAgentId) {
7386
7490
  this.agentId = providedAgentId ?? options.agentId ?? generateCloudAgentId();
7387
- this.model = options.model;
7491
+ this.model = normalizeModel(options.model);
7388
7492
  this.options = options;
7389
7493
  this.cloudPayload = serializeCloudAgentConfig({ ...options, agentId: this.agentId });
7390
7494
  const repoUrls = (options.cloud?.repos ?? []).map((repo) => repo.url);
@@ -7414,6 +7518,17 @@ var CloudAgent = class {
7414
7518
  const apiKey = resolveApiKey(this.options.apiKey);
7415
7519
  return isFixtureApiKey(apiKey) && getConfiguredBaseUrl() === void 0;
7416
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
+ }
7417
7532
  async send(message, options = {}) {
7418
7533
  if (options.tools !== void 0 && options.tools.length > 0) {
7419
7534
  throw new exports.ConfigurationError(
@@ -7444,7 +7559,7 @@ var CloudAgent = class {
7444
7559
  });
7445
7560
  }
7446
7561
  async sendLocked(message, options) {
7447
- const overrideModel = options.model;
7562
+ const overrideModel = normalizeModel(options.model);
7448
7563
  if (overrideModel !== void 0) {
7449
7564
  this.model = overrideModel;
7450
7565
  updateRegisteredAgent(this.agentId, { model: overrideModel });
@@ -8361,18 +8476,18 @@ var ALL_ADAPTERS = [
8361
8476
  arizeAdapter,
8362
8477
  braintrustAdapter
8363
8478
  ];
8364
- var registered = /* @__PURE__ */ new Set();
8479
+ var registered2 = /* @__PURE__ */ new Set();
8365
8480
  function tryAutoRegisterAdapters(settings) {
8366
8481
  if (settings?.enabled !== true) return;
8367
8482
  if (settings.autoDetect === false) return;
8368
8483
  const disabled = new Set(settings.disable ?? []);
8369
8484
  for (const adapter of ALL_ADAPTERS) {
8370
- if (registered.has(adapter.moduleName)) continue;
8485
+ if (registered2.has(adapter.moduleName)) continue;
8371
8486
  if (disabled.has(adapter.displayName.toLowerCase())) continue;
8372
8487
  if (!adapter.detect()) continue;
8373
8488
  try {
8374
8489
  adapter.register();
8375
- registered.add(adapter.moduleName);
8490
+ registered2.add(adapter.moduleName);
8376
8491
  process.stderr.write(`[theokit-sdk] telemetry: ${adapter.displayName} auto-instrumented.
8377
8492
  `);
8378
8493
  } catch (cause) {
@@ -8902,6 +9017,26 @@ function paginate(items, opts) {
8902
9017
  return items.slice(start, end);
8903
9018
  }
8904
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
+
8905
9040
  // src/internal/persistence/conversation-storage-fs.ts
8906
9041
  var FileSystemConversationStorage = class {
8907
9042
  #root;
@@ -8952,6 +9087,37 @@ var FileSystemConversationStorage = class {
8952
9087
  async compact(conversationId, maxTurns) {
8953
9088
  await compactSessionFile(this.#root, conversationId, maxTurns);
8954
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
+ }
8955
9121
  async dispose() {
8956
9122
  }
8957
9123
  };
@@ -10803,23 +10969,27 @@ function tryParseSkill(raw, fallbackName, source, options) {
10803
10969
 
10804
10970
  // src/internal/runtime/skills/skills-manager.ts
10805
10971
  var SkillsManager = class {
10806
- constructor(cwd, _enabled, settingSourcesIncludeProject) {
10972
+ constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
10807
10973
  this.cwd = cwd;
10808
10974
  this.settingSourcesIncludeProject = settingSourcesIncludeProject;
10975
+ this.skillsDir = skillsDir;
10976
+ this.inline = inline;
10809
10977
  }
10810
10978
  cwd;
10811
10979
  settingSourcesIncludeProject;
10980
+ skillsDir;
10981
+ inline;
10812
10982
  skills = [];
10813
10983
  async initialize() {
10814
10984
  if (!this.settingSourcesIncludeProject) {
10815
- this.skills = [];
10985
+ this.skills = this.mergeInline([]);
10816
10986
  return;
10817
10987
  }
10818
10988
  await this.refresh();
10819
10989
  }
10820
10990
  async refresh() {
10821
- const skillsRoot = path.join(this.cwd, ".theokit", "skills");
10822
- this.skills = await discoverSkills(skillsRoot, {
10991
+ const skillsRoot = this.skillsDir ?? path.join(this.cwd, ".theokit", "skills");
10992
+ const discovered = await discoverSkills(skillsRoot, {
10823
10993
  onInvalidSkill: (info) => {
10824
10994
  process.stderr.write(
10825
10995
  `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
@@ -10827,6 +10997,13 @@ var SkillsManager = class {
10827
10997
  );
10828
10998
  }
10829
10999
  });
11000
+ this.skills = this.mergeInline(discovered);
11001
+ }
11002
+ /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
11003
+ mergeInline(discovered) {
11004
+ if (this.inline === void 0 || this.inline.length === 0) return discovered;
11005
+ const inlineNames = new Set(this.inline.map((s) => s.name));
11006
+ return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
10830
11007
  }
10831
11008
  list() {
10832
11009
  return Promise.resolve(this.skills);
@@ -10862,7 +11039,7 @@ function bootstrapSubmanagers(args) {
10862
11039
  const providerCount = (args.options.providers?.routes?.length ?? 0) + enabledPluginNames(args.options.plugins).length;
10863
11040
  if (providerCount > 0 || args.options.providers !== void 0) {
10864
11041
  out.providers = new ProvidersManagerImpl(
10865
- args.options.model,
11042
+ normalizeModel(args.options.model),
10866
11043
  args.options.providers,
10867
11044
  args.options.plugins
10868
11045
  );
@@ -10871,7 +11048,10 @@ function bootstrapSubmanagers(args) {
10871
11048
  out.skillsManager = new SkillsManager(
10872
11049
  args.workspaceCwd,
10873
11050
  args.options.skills?.enabled,
10874
- args.settingSourcesIncludeProject
11051
+ args.settingSourcesIncludeProject,
11052
+ // M22 — custom skills directory + inline (code-defined) skills.
11053
+ args.options.skills?.skillsDir,
11054
+ args.options.skills?.inline
10875
11055
  );
10876
11056
  const localSkills = out.skillsManager;
10877
11057
  out.skills = { list: () => localSkills.list() };
@@ -10929,6 +11109,7 @@ function createLocalRun(options) {
10929
11109
  projectMcpServers: options.projectMcpServers,
10930
11110
  ...options.persistMemoryFact !== void 0 ? { persistMemoryFact: options.persistMemoryFact } : {}
10931
11111
  });
11112
+ if (options.sendOptions.origin !== void 0) script.origin = options.sendOptions.origin;
10932
11113
  const handle = new LocalRun({
10933
11114
  id,
10934
11115
  agentId: options.agentId,
@@ -11577,6 +11758,15 @@ async function emitReasoningDeltaCallback(inputs, text) {
11577
11758
  );
11578
11759
  }
11579
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
+
11580
11770
  // src/internal/agent-loop/tool-dispatch.ts
11581
11771
  init_async_local_storage();
11582
11772
 
@@ -11674,6 +11864,22 @@ function coerceArgsToSchema(args, schema) {
11674
11864
  return { value: out, changed };
11675
11865
  }
11676
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
+
11677
11883
  // src/internal/runtime/tools/shell-tool.ts
11678
11884
  async function runShell(options) {
11679
11885
  if (options.sandbox === true && isObviouslyUnsafe(options.command)) {
@@ -11727,9 +11933,13 @@ async function runHandlerTool(kind, handler, call, signal, context) {
11727
11933
  return { stdout: "", stderr: `${kind} tool ${call.name} has no handler`, exitCode: 127 };
11728
11934
  }
11729
11935
  try {
11730
- const stdout = await handler(call.input, { signal, context });
11731
- 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 };
11732
11939
  } catch (cause) {
11940
+ if (cause instanceof ToolError) {
11941
+ return { stdout: "", stderr: cause.message, exitCode: 1, content: cause.content };
11942
+ }
11733
11943
  const message = cause instanceof Error ? cause.message : String(cause);
11734
11944
  return { stdout: "", stderr: message, exitCode: 1 };
11735
11945
  }
@@ -11848,6 +12058,11 @@ async function dispatchSingleCall(inputs, tools, call, events, parentSpan) {
11848
12058
  toolSpan?.end();
11849
12059
  return fileVeto;
11850
12060
  }
12061
+ emitRunEvent(inputs.runEventSink, {
12062
+ type: "tool_progress",
12063
+ toolName: workingCall.name,
12064
+ toolCallId: callId
12065
+ });
11851
12066
  const result = await runToolWithLifecycle(inputs, resolved, workingCall, callId);
11852
12067
  await inputs.pluginManager?.runPostToolCallHooks({
11853
12068
  name: workingCall.name,
@@ -11874,6 +12089,13 @@ function applyRepairAndExtractCall(tools, call) {
11874
12089
  function vetoFromForkWhitelist(inputs, call, callId, events) {
11875
12090
  const whitelistDecision = checkToolWhitelist(call.name);
11876
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
+ });
11877
12099
  events.push(buildToolUseRunning(inputs, callId, call));
11878
12100
  events.push(
11879
12101
  buildToolUseCompleted(inputs, callId, call, {
@@ -11910,6 +12132,13 @@ async function vetoFromPluginPreHook(inputs, call, callId, events) {
11910
12132
  runId: inputs.runId
11911
12133
  });
11912
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
+ });
11913
12142
  events.push(
11914
12143
  buildToolUseCompleted(inputs, callId, call, {
11915
12144
  stdout: "",
@@ -11932,6 +12161,13 @@ async function vetoFromFileHookPreDecision(inputs, call, callId, events) {
11932
12161
  runId: inputs.runId
11933
12162
  });
11934
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
+ });
11935
12171
  events.push(
11936
12172
  buildToolUseCompleted(inputs, callId, call, {
11937
12173
  stdout: "",
@@ -11975,7 +12211,9 @@ async function runToolWithLifecycle(inputs, resolved, call, callId) {
11975
12211
  await safeEmitToolHook(inputs.onToolEnd, {
11976
12212
  toolName: call.name,
11977
12213
  args: call.input,
11978
- 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,
11979
12217
  conversationId: inputs.agentId,
11980
12218
  callId,
11981
12219
  durationMs
@@ -11997,7 +12235,10 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
11997
12235
  output: {
11998
12236
  stdout: result.stdout,
11999
12237
  stderr: result.stderr,
12000
- 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 } : {}
12001
12242
  },
12002
12243
  agentId: inputs.agentId,
12003
12244
  runId: inputs.runId
@@ -12010,7 +12251,9 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
12010
12251
  return {
12011
12252
  type: "tool_result",
12012
12253
  toolUseId: call.id,
12013
- 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),
12014
12257
  ...result.exitCode !== 0 && result.exitCode !== void 0 ? { isError: true } : {}
12015
12258
  };
12016
12259
  }
@@ -12059,6 +12302,29 @@ function buildToolUseCompleted(inputs, callId, call, result) {
12059
12302
  };
12060
12303
  }
12061
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
+
12062
12328
  // src/internal/agent-loop/tool-result-guard.ts
12063
12329
  var OPEN = "<untrusted-tool-output>";
12064
12330
  var CLOSE = "</untrusted-tool-output>";
@@ -12084,7 +12350,11 @@ ${CLOSE}`;
12084
12350
  function applyToolResultGuard(parts, opts) {
12085
12351
  if (opts.delimit !== true && opts.redactPii !== true) return parts;
12086
12352
  return parts.map(
12087
- (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
+ )
12088
12358
  );
12089
12359
  }
12090
12360
 
@@ -13015,10 +13285,10 @@ function stripVertexPrefix(modelId) {
13015
13285
  }
13016
13286
 
13017
13287
  // src/internal/providers/builtin/index.ts
13018
- var registered2 = false;
13288
+ var registered3 = false;
13019
13289
  function registerBuiltins() {
13020
- if (registered2) return;
13021
- registered2 = true;
13290
+ if (registered3) return;
13291
+ registered3 = true;
13022
13292
  registerProvider(ANTHROPIC);
13023
13293
  registerProvider(OPENAI);
13024
13294
  registerProvider(OPENROUTER);
@@ -13247,7 +13517,9 @@ function toAnthropicWireMessage(message) {
13247
13517
  return {
13248
13518
  type: "tool_result",
13249
13519
  tool_use_id: part.toolUseId,
13250
- 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),
13251
13523
  ...part.isError === true ? { is_error: true } : {}
13252
13524
  };
13253
13525
  });
@@ -14039,7 +14311,8 @@ function toOllamaMessages(message) {
14039
14311
  if (part.type === "tool_result") {
14040
14312
  out.push({
14041
14313
  role: "tool",
14042
- content: part.content,
14314
+ // SE7 — string-only tool role: text blocks flatten; image fails fast.
14315
+ content: toStringToolResultContent(part.content, "ollama"),
14043
14316
  tool_name: part.toolUseId
14044
14317
  });
14045
14318
  }
@@ -14576,7 +14849,9 @@ function userOrToolMessages(message) {
14576
14849
  out.push({
14577
14850
  role: "tool",
14578
14851
  tool_call_id: part.toolUseId,
14579
- 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")
14580
14855
  });
14581
14856
  }
14582
14857
  }
@@ -15506,18 +15781,20 @@ function levenshtein(a, b) {
15506
15781
  function createRealLocalRun(options) {
15507
15782
  const { userText, id, startTime } = prepareRunContext(options.message);
15508
15783
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
15509
- const unusedFixtureScript = {
15784
+ const runScript = {
15510
15785
  events: [],
15511
15786
  finalStatus: "running",
15512
15787
  cancellable: false,
15513
- 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 } : {}
15514
15791
  };
15515
15792
  const handle = new RealLocalRun(
15516
15793
  {
15517
15794
  id,
15518
15795
  agentId: options.agentId,
15519
15796
  model: options.model,
15520
- script: unusedFixtureScript,
15797
+ script: runScript,
15521
15798
  supportedOps: supported,
15522
15799
  startTime
15523
15800
  },
@@ -15629,6 +15906,8 @@ function buildLoopInputs(options, runId, userText) {
15629
15906
  // M7 — forward SendOptions.context to the loop so every tool handler receives
15630
15907
  // it on `ctx.context` (shared run config set once, e.g. projectRoot).
15631
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 } : {},
15632
15911
  // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
15633
15912
  // can enable them via SendOptions (not only internal AgentLoopInputs).
15634
15913
  ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
@@ -17373,7 +17652,7 @@ function wrapRunWithPostReplyHook(args) {
17373
17652
  async function executeSendLocked(inputs, message, options) {
17374
17653
  if (inputs.disposed) throw new exports.AgentDisposedError(inputs.agentId);
17375
17654
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
17376
- inputs.applyModelOverride(options.model);
17655
+ inputs.applyModelOverride(normalizeModel(options.model));
17377
17656
  const userText = typeof message === "string" ? message : message.text;
17378
17657
  if (inputs.options.onBeforeSend !== void 0) {
17379
17658
  await inputs.options.onBeforeSend({
@@ -17525,7 +17804,7 @@ var LocalAgent = class {
17525
17804
  constructor(options) {
17526
17805
  this.agentId = options.agentId ?? generateLocalAgentId();
17527
17806
  this._telemetry = createTelemetry(options.telemetry);
17528
- this.model = options.model;
17807
+ this.model = normalizeModel(options.model);
17529
17808
  this.options = options;
17530
17809
  this.workspaceCwd = resolveCwd(options.local?.cwd);
17531
17810
  this.conversationStorage = options.conversationStorage;
@@ -17592,6 +17871,11 @@ var LocalAgent = class {
17592
17871
  hooks() {
17593
17872
  return this.hooksExecutor;
17594
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
+ }
17595
17879
  async send(message, options = {}) {
17596
17880
  if (options.tools !== void 0 && options.tools.length > 0) {
17597
17881
  validateToolCatalog(options.tools);
@@ -17831,6 +18115,7 @@ function includesSetting(options, source) {
17831
18115
 
17832
18116
  // src/agent-helpers.ts
17833
18117
  async function runCreateUnderSpan(options, span) {
18118
+ options = { ...options, model: normalizeModel(options.model) };
17834
18119
  validateAgentOptions(options);
17835
18120
  validateCloudToolParity(options);
17836
18121
  await guardAgainstIdCollision(options);
@@ -17904,7 +18189,10 @@ async function createLocalAgent(options) {
17904
18189
  const willFlowToProvider = !isFixtureApiKey(apiKey) && !shouldUseRealLocalRuntime(apiKey);
17905
18190
  const shape = validateApiKeyShape(apiKey, {
17906
18191
  strict: willFlowToProvider,
17907
- ...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) } : {}
17908
18196
  });
17909
18197
  if (shape.malformed) {
17910
18198
  throw new exports.AuthenticationError(shape.message, { code: "malformed_api_key" });
@@ -17970,6 +18258,10 @@ async function rehydrateExistingAgent(agentId, existing, options) {
17970
18258
  ...existing.options,
17971
18259
  ...options,
17972
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),
17973
18265
  mcpServers: void 0,
17974
18266
  agentId
17975
18267
  };
@@ -18336,6 +18628,7 @@ async function getOrCreateUncached(agentId, options) {
18336
18628
  }
18337
18629
  setAgentFacade({
18338
18630
  create: (options) => Agent.create(options),
18631
+ delete: (agentId) => Agent.delete(agentId),
18339
18632
  prompt: (message, options) => Agent.prompt(message, options),
18340
18633
  get: (agentId) => Agent.get(agentId),
18341
18634
  resume: (agentId, options) => Agent.resume(agentId, options),
@@ -18773,6 +19066,20 @@ var Budget = class {
18773
19066
  }
18774
19067
  };
18775
19068
 
19069
+ // src/create-skill.ts
19070
+ function createSkill(spec) {
19071
+ if (!spec.name) throw new Error("createSkill: `name` is required.");
19072
+ if (!spec.description) throw new Error("createSkill: `description` is required.");
19073
+ return {
19074
+ name: spec.name,
19075
+ description: spec.description,
19076
+ source: `inline://${spec.name}`,
19077
+ instructions: spec.instructions,
19078
+ ...spec.category !== void 0 ? { category: spec.category } : {},
19079
+ ...spec.dependencies !== void 0 ? { dependencies: spec.dependencies } : {}
19080
+ };
19081
+ }
19082
+
18776
19083
  // src/cron.ts
18777
19084
  init_errors();
18778
19085
 
@@ -19282,6 +19589,8 @@ init_generate_object();
19282
19589
  // src/internal/persistence/conversation-storage-memory.ts
19283
19590
  var InMemoryConversationStorage = class {
19284
19591
  #store = /* @__PURE__ */ new Map();
19592
+ // SE4 — session-level metadata (title/tag), kept beside the transcript.
19593
+ #meta = /* @__PURE__ */ new Map();
19285
19594
  async getMessages(conversationId, opts) {
19286
19595
  const existing = this.#store.get(conversationId);
19287
19596
  return existing === void 0 ? [] : paginate(existing.slice(), opts);
@@ -19310,15 +19619,20 @@ var InMemoryConversationStorage = class {
19310
19619
  }
19311
19620
  async deleteConversation(conversationId) {
19312
19621
  this.#store.delete(conversationId);
19622
+ this.#meta.delete(conversationId);
19313
19623
  }
19314
19624
  async deleteScope(prefix) {
19315
19625
  let n = 0;
19316
19626
  for (const id of [...this.#store.keys()]) {
19317
19627
  if (id.startsWith(prefix)) {
19318
19628
  this.#store.delete(id);
19629
+ this.#meta.delete(id);
19319
19630
  n += 1;
19320
19631
  }
19321
19632
  }
19633
+ for (const id of [...this.#meta.keys()]) {
19634
+ if (id.startsWith(prefix)) this.#meta.delete(id);
19635
+ }
19322
19636
  return n;
19323
19637
  }
19324
19638
  async listConversationIds(opts) {
@@ -19326,8 +19640,17 @@ var InMemoryConversationStorage = class {
19326
19640
  if (opts?.limit !== void 0) return all.slice(0, opts.limit);
19327
19641
  return all;
19328
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
+ }
19329
19651
  async dispose() {
19330
19652
  this.#store.clear();
19653
+ this.#meta.clear();
19331
19654
  }
19332
19655
  };
19333
19656
 
@@ -20067,6 +20390,21 @@ async function migrateSqliteToLance2(options) {
20067
20390
  }
20068
20391
 
20069
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
+ }
20070
20408
  function argMatches(matcher, value) {
20071
20409
  if (typeof matcher === "function") return matcher(value);
20072
20410
  if (value === void 0) return false;
@@ -20087,14 +20425,14 @@ var PermissionEngine = class {
20087
20425
  * argument values, so the same tool name can resolve to different actions
20088
20426
  * depending on what it is asked to do.
20089
20427
  */
20090
- evaluate(toolName, args) {
20428
+ evaluate(toolName, args, mode = "default") {
20091
20429
  for (const rule of this.rules) {
20092
20430
  const nameMatches = typeof rule.tool === "string" ? rule.tool === toolName : rule.tool.test(toolName);
20093
20431
  if (!nameMatches) continue;
20094
20432
  if (rule.args !== void 0 && !this.#argsMatch(rule.args, args)) continue;
20095
- return rule.action;
20433
+ return applyMode(rule.action, mode, true);
20096
20434
  }
20097
- return this.defaultAction;
20435
+ return applyMode(this.defaultAction, mode, false);
20098
20436
  }
20099
20437
  #argsMatch(matchers, args) {
20100
20438
  const call = args ?? {};
@@ -20106,27 +20444,85 @@ var PermissionEngine = class {
20106
20444
  };
20107
20445
 
20108
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
+ }
20109
20459
  function createPermissionPlugin(engine, opts = {}) {
20460
+ const mode = opts.mode ?? "default";
20110
20461
  return definePlugin({
20111
20462
  name: opts.name ?? "permission-engine",
20112
20463
  version: "1.0.0",
20113
20464
  kind: "general",
20114
20465
  register(ctx) {
20115
- ctx.on("pre_tool_call", (rawCtx) => {
20466
+ ctx.on("pre_tool_call", async (rawCtx) => {
20116
20467
  const { name, args } = rawCtx;
20117
- const action = engine.evaluate(name, args);
20468
+ const action = engine.evaluate(name, args, mode);
20118
20469
  if (action === "deny") {
20119
20470
  return { block: true, message: `denied by permission engine: ${name}` };
20120
20471
  }
20121
- if (action === "ask") {
20122
- return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20123
- }
20472
+ if (action === "ask") return resolveAsk(opts, name, args, mode);
20124
20473
  return void 0;
20125
20474
  });
20126
20475
  }
20127
20476
  });
20128
20477
  }
20129
20478
 
20479
+ // src/schema-normalizer.ts
20480
+ init_to_json_schema();
20481
+ function isJsonSchemaObject(s) {
20482
+ if (typeof s !== "object" || s === null) return false;
20483
+ const o = s;
20484
+ if ("$schema" in o) return true;
20485
+ return o.type === "object" && typeof o.properties === "object" && o.properties !== null;
20486
+ }
20487
+ function hasToJsonSchemaMethod(s) {
20488
+ return typeof s === "object" && s !== null && typeof s.toJsonSchema === "function";
20489
+ }
20490
+ function isZodSchema(s) {
20491
+ if (typeof s !== "object" || s === null) return false;
20492
+ const o = s;
20493
+ return typeof o.safeParse === "function" && ("_def" in o || "def" in o);
20494
+ }
20495
+ function isValibotSchema(s) {
20496
+ if (typeof s !== "object" || s === null) return false;
20497
+ const o = s;
20498
+ return o.kind === "schema" && "type" in o && typeof o.toJsonSchema !== "function";
20499
+ }
20500
+ async function normalizeSchema(schema) {
20501
+ if (isJsonSchemaObject(schema)) return schema;
20502
+ if (isValibotSchema(schema)) {
20503
+ const specifier = "@valibot/to-json-schema";
20504
+ try {
20505
+ const mod = await import(specifier);
20506
+ return mod.toJsonSchema(schema);
20507
+ } catch (err) {
20508
+ const missing = err instanceof Error && /Cannot find|Cannot resolve|ERR_MODULE_NOT_FOUND/.test(err.message);
20509
+ if (missing) {
20510
+ throw new Error(
20511
+ "normalizeSchema: a Valibot schema requires the optional '@valibot/to-json-schema' package. Install it, or use a Zod schema (the default recommendation)."
20512
+ );
20513
+ }
20514
+ throw err;
20515
+ }
20516
+ }
20517
+ if (isZodSchema(schema)) {
20518
+ return toJsonSchema(schema, { unrepresentable: "any" });
20519
+ }
20520
+ if (hasToJsonSchemaMethod(schema)) return schema.toJsonSchema();
20521
+ throw new Error(
20522
+ "normalizeSchema: unsupported schema. Supported: Zod (default), JSON Schema, ArkType (.toJsonSchema()), Valibot (with @valibot/to-json-schema)."
20523
+ );
20524
+ }
20525
+
20130
20526
  // src/security.ts
20131
20527
  init_security();
20132
20528
  var Security = class {
@@ -20179,6 +20575,96 @@ var Security = class {
20179
20575
  }
20180
20576
  };
20181
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
+
20182
20668
  // src/session-scope.ts
20183
20669
  function scopedConversationId(scope, id) {
20184
20670
  return `${scope}__${id}`;
@@ -20199,7 +20685,7 @@ var PersistenceSchema = zod.z.object({
20199
20685
  // src/workflow.ts
20200
20686
  init_path_guard();
20201
20687
  init_workflow();
20202
- zod.z.object({
20688
+ var RetryPolicySchema = zod.z.object({
20203
20689
  // EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
20204
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"),
20205
20691
  initialBackoffMs: zod.z.number().int().min(0).optional(),
@@ -20397,12 +20883,15 @@ var Workflow = class {
20397
20883
  };
20398
20884
  function agentStep(id, agent, promptTemplate, opts) {
20399
20885
  validateStepId(id);
20886
+ if (opts?.retry !== void 0) RetryPolicySchema.parse(opts.retry);
20400
20887
  return {
20401
20888
  kind: "agent",
20402
20889
  id,
20403
20890
  agent,
20404
20891
  promptTemplate,
20405
- ...{}
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 } : {}
20406
20895
  };
20407
20896
  }
20408
20897
  function validateStepId(id) {
@@ -20450,7 +20939,8 @@ function createSquad(options) {
20450
20939
  for (let i = 0; i < agents2.length; i++) {
20451
20940
  const agent = agents2[i];
20452
20941
  if (agent === void 0) continue;
20453
- 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));
20454
20944
  }
20455
20945
  const run = await builder.commit().run(input);
20456
20946
  return { result: run.output, status: run.status, steps: run.stepResults };
@@ -20917,7 +21407,9 @@ exports.PermissionEngine = PermissionEngine;
20917
21407
  exports.Security = Security;
20918
21408
  exports.Task = Task;
20919
21409
  exports.Theokit = Theokit;
21410
+ exports.ToolError = ToolError;
20920
21411
  exports.UsageAccumulator = UsageAccumulator;
21412
+ exports.applyMode = applyMode;
20921
21413
  exports.buildReplayHistory = buildReplayHistory;
20922
21414
  exports.chargeAndCheckThresholds = chargeAndCheckThresholds;
20923
21415
  exports.computeCost = computeCost;
@@ -20925,16 +21417,20 @@ exports.createAgentFactory = createAgentFactory;
20925
21417
  exports.createCounterBudgetTracker = createCounterBudgetTracker;
20926
21418
  exports.createNoopMemoryProvider = createNoopMemoryProvider;
20927
21419
  exports.createPermissionPlugin = createPermissionPlugin;
21420
+ exports.createSessionManager = createSessionManager;
21421
+ exports.createSkill = createSkill;
20928
21422
  exports.createSquad = createSquad;
20929
21423
  exports.definePlugin = definePlugin;
20930
21424
  exports.defineProvider = defineProvider;
20931
21425
  exports.defineTool = defineTool;
21426
+ exports.emitRunEvent = emitRunEvent;
20932
21427
  exports.extractRawId = extractRawId;
20933
21428
  exports.getPricingEntry = getPricingEntry;
20934
21429
  exports.inferApiMode = inferApiMode;
20935
21430
  exports.isTransientError = isTransientError;
20936
21431
  exports.migrateSqliteToLance = migrateSqliteToLance2;
20937
21432
  exports.mkMemoryId = mkMemoryId;
21433
+ exports.normalizeSchema = normalizeSchema;
20938
21434
  exports.normalizeUsage = normalizeUsage;
20939
21435
  exports.preflightCheck = preflightCheck;
20940
21436
  exports.scopedConversationId = scopedConversationId;