@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.js CHANGED
@@ -1,10 +1,10 @@
1
+ import { z, toJSONSchema } from 'zod';
2
+ import { createRequire } from 'module';
1
3
  import { createHash, randomUUID, randomBytes } from 'crypto';
2
4
  import { existsSync, rmSync, mkdirSync, renameSync, readFileSync, realpathSync, lstatSync, readlinkSync, readdirSync } from 'fs';
3
5
  import { join, dirname, relative, resolve, sep, isAbsolute } from 'path';
4
- import { readFile, stat, rm, readdir, mkdir, rename, open, unlink, statfs, access, appendFile } from 'fs/promises';
5
- import { z, toJSONSchema } from 'zod';
6
+ import { readFile, stat, rm, readdir, mkdir, appendFile, rename, open, unlink, statfs, access, writeFile } from 'fs/promises';
6
7
  import { AsyncLocalStorage } from 'async_hooks';
7
- import { createRequire } from 'module';
8
8
  import { homedir } from 'os';
9
9
  import { spawn } from 'child_process';
10
10
  import { fileURLToPath } from 'url';
@@ -516,6 +516,256 @@ var init_errors = __esm({
516
516
  };
517
517
  }
518
518
  });
519
+ function toJsonSchema(schema, options = { unrepresentable: "any" }) {
520
+ return toJSONSchema(schema, options);
521
+ }
522
+ var init_to_json_schema = __esm({
523
+ "src/internal/zod/to-json-schema.ts"() {
524
+ }
525
+ });
526
+ function requireZod() {
527
+ if (cachedZ !== void 0) return cachedZ;
528
+ const r = createRequire(import.meta.url);
529
+ let mod;
530
+ try {
531
+ mod = r("zod");
532
+ } catch (cause) {
533
+ throw new ConfigurationError(
534
+ 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
535
+ { code: "zod_not_installed", cause }
536
+ );
537
+ }
538
+ cachedZ = mod.z ?? mod;
539
+ return cachedZ;
540
+ }
541
+ function makeOutputTool(jsonSchema, onCapture) {
542
+ return {
543
+ name: "output",
544
+ description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
545
+ inputSchema: jsonSchema,
546
+ handler: (input) => {
547
+ const out = onCapture(input);
548
+ if (typeof out === "string") return out;
549
+ if (out instanceof Promise) return out;
550
+ return "";
551
+ }
552
+ };
553
+ }
554
+ function buildTransientAgentOptions(params) {
555
+ return {
556
+ model: params.model,
557
+ local: params.local,
558
+ tools: [params.outputTool],
559
+ systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
560
+ ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
561
+ ...params.providers !== void 0 ? { providers: params.providers } : {}
562
+ };
563
+ }
564
+ function extractUsage(result) {
565
+ const u = result.usage;
566
+ if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
567
+ return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
568
+ }
569
+ function buildToolPrompt(prompt) {
570
+ return `${prompt}
571
+
572
+ Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
573
+ }
574
+ function setupStructuredOutput(schema, maxRetries) {
575
+ const z8 = requireZod();
576
+ const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
577
+ return {
578
+ z: z8,
579
+ jsonSchema,
580
+ maxRetries: maxRetries ?? 1,
581
+ initialUsage: { inputTokens: 0, outputTokens: 0 }
582
+ };
583
+ }
584
+ async function disposeAndDeleteTransient(agent, deletor) {
585
+ await agent.dispose();
586
+ try {
587
+ await deletor(agent.agentId);
588
+ } catch {
589
+ }
590
+ }
591
+ var cachedZ;
592
+ var init_structured_output_helpers = __esm({
593
+ "src/internal/structured-output-helpers.ts"() {
594
+ init_errors();
595
+ init_to_json_schema();
596
+ }
597
+ });
598
+
599
+ // src/generate-object.ts
600
+ var generate_object_exports = {};
601
+ __export(generate_object_exports, {
602
+ GenerateObjectError: () => GenerateObjectError,
603
+ generateObjectImpl: () => generateObjectImpl
604
+ });
605
+ function salvagePartial(schema, raw) {
606
+ if (typeof raw !== "object" || raw === null) return raw;
607
+ const shape = schema.shape;
608
+ if (shape === void 0 || typeof shape !== "object") return raw;
609
+ const rawObj = raw;
610
+ const out = {};
611
+ for (const [key2, fieldSchema] of Object.entries(shape)) {
612
+ if (typeof fieldSchema?.safeParse !== "function") continue;
613
+ const parsed = fieldSchema.safeParse(rawObj[key2]);
614
+ if (parsed.success) out[key2] = parsed.data;
615
+ }
616
+ return out;
617
+ }
618
+ async function runReasoningPhase(options, deps) {
619
+ const reasoningOptions = {
620
+ model: options.model,
621
+ local: options.local,
622
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
623
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
624
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
625
+ };
626
+ const reasoningAgent = await deps.create(reasoningOptions);
627
+ try {
628
+ const run = await reasoningAgent.send(options.prompt);
629
+ const result = await run.wait();
630
+ const text = result.result;
631
+ return typeof text === "string" ? text : options.prompt;
632
+ } finally {
633
+ await disposeAndDeleteTransient(reasoningAgent, deps.delete);
634
+ }
635
+ }
636
+ async function generateObjectImpl(options, deps) {
637
+ const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
638
+ options.schema,
639
+ options.maxRetries
640
+ );
641
+ let capturedRaw;
642
+ let lastUsage = initialUsage;
643
+ const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
644
+ class CaptureSentinel extends Error {
645
+ constructor(captured) {
646
+ super("generate-object-capture");
647
+ this.captured = captured;
648
+ }
649
+ captured;
650
+ [sentinel] = true;
651
+ }
652
+ const outputTool = makeOutputTool(jsonSchema, (input) => {
653
+ if (capturedRaw === void 0) {
654
+ capturedRaw = input;
655
+ }
656
+ throw new CaptureSentinel(input);
657
+ });
658
+ const reasoningText = options.structuringModel !== void 0 ? await runReasoningPhase(options, deps) : void 0;
659
+ const structuringModel = options.structuringModel ?? options.model;
660
+ const structuringPrompt = reasoningText ?? options.prompt;
661
+ const agentOptions = buildTransientAgentOptions({
662
+ model: structuringModel,
663
+ local: options.local,
664
+ outputTool,
665
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
666
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
667
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
668
+ });
669
+ const agent = await deps.create(agentOptions);
670
+ try {
671
+ const userMessage = buildToolPrompt(structuringPrompt);
672
+ let lastParseError;
673
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
674
+ capturedRaw = void 0;
675
+ const run = await agent.send(userMessage);
676
+ const result = await run.wait();
677
+ lastUsage = extractUsage(result);
678
+ if (capturedRaw === void 0) {
679
+ if (result.status === "error" && result.error !== void 0) {
680
+ throw new GenerateObjectError(
681
+ "no_tool_call",
682
+ `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
683
+ result.error
684
+ );
685
+ }
686
+ if (attempt === maxRetries) {
687
+ throw new GenerateObjectError(
688
+ "no_tool_call",
689
+ "The model returned text instead of calling the `output` tool."
690
+ );
691
+ }
692
+ continue;
693
+ }
694
+ const parsed = options.schema.safeParse(capturedRaw);
695
+ if (parsed.success) {
696
+ return {
697
+ object: parsed.data,
698
+ raw: capturedRaw,
699
+ usage: lastUsage,
700
+ finishReason: "tool_use"
701
+ };
702
+ }
703
+ lastParseError = parsed.error;
704
+ }
705
+ if (options.errorStrategy === "return-raw") {
706
+ return {
707
+ object: capturedRaw,
708
+ raw: capturedRaw,
709
+ usage: lastUsage,
710
+ finishReason: "tool_use"
711
+ };
712
+ }
713
+ if (options.errorStrategy === "return-partial") {
714
+ return {
715
+ object: salvagePartial(options.schema, capturedRaw),
716
+ raw: capturedRaw,
717
+ usage: lastUsage,
718
+ finishReason: "tool_use"
719
+ };
720
+ }
721
+ throw new GenerateObjectError(
722
+ "parse_failed",
723
+ "Schema parse failed after all retries.",
724
+ lastParseError
725
+ );
726
+ } finally {
727
+ await disposeAndDeleteTransient(agent, deps.delete);
728
+ }
729
+ }
730
+ var GenerateObjectError;
731
+ var init_generate_object = __esm({
732
+ "src/generate-object.ts"() {
733
+ init_structured_output_helpers();
734
+ GenerateObjectError = class extends Error {
735
+ name = "GenerateObjectError";
736
+ code;
737
+ cause;
738
+ constructor(code, message, cause) {
739
+ super(message);
740
+ this.code = code;
741
+ if (cause !== void 0) this.cause = cause;
742
+ }
743
+ };
744
+ }
745
+ });
746
+
747
+ // src/internal/runtime/registry/agent-factory-registry.ts
748
+ var agent_factory_registry_exports = {};
749
+ __export(agent_factory_registry_exports, {
750
+ getAgentFacade: () => getAgentFacade,
751
+ setAgentFacade: () => setAgentFacade
752
+ });
753
+ function setAgentFacade(facade) {
754
+ registered = facade;
755
+ }
756
+ function getAgentFacade() {
757
+ if (registered === void 0) {
758
+ throw new Error(
759
+ "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
760
+ );
761
+ }
762
+ return registered;
763
+ }
764
+ var registered;
765
+ var init_agent_factory_registry = __esm({
766
+ "src/internal/runtime/registry/agent-factory-registry.ts"() {
767
+ }
768
+ });
519
769
 
520
770
  // src/internal/persistence/cwd-mutex.ts
521
771
  function withCwdMutex(key2, fn) {
@@ -2786,29 +3036,6 @@ var init_judge_call = __esm({
2786
3036
  }
2787
3037
  });
2788
3038
 
2789
- // src/internal/runtime/registry/agent-factory-registry.ts
2790
- var agent_factory_registry_exports = {};
2791
- __export(agent_factory_registry_exports, {
2792
- getAgentFacade: () => getAgentFacade,
2793
- setAgentFacade: () => setAgentFacade
2794
- });
2795
- function setAgentFacade(facade) {
2796
- registered3 = facade;
2797
- }
2798
- function getAgentFacade() {
2799
- if (registered3 === void 0) {
2800
- throw new Error(
2801
- "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
2802
- );
2803
- }
2804
- return registered3;
2805
- }
2806
- var registered3;
2807
- var init_agent_factory_registry = __esm({
2808
- "src/internal/runtime/registry/agent-factory-registry.ts"() {
2809
- }
2810
- });
2811
-
2812
3039
  // src/internal/runtime/lifecycle/run-to-completion.ts
2813
3040
  var run_to_completion_exports = {};
2814
3041
  __export(run_to_completion_exports, {
@@ -2973,14 +3200,14 @@ async function forkAgentImpl(parent, options, deps) {
2973
3200
  return {
2974
3201
  result: result.result,
2975
3202
  toolCalls: [],
2976
- usage: extractUsage(result)
3203
+ usage: extractUsage2(result)
2977
3204
  };
2978
3205
  });
2979
3206
  } finally {
2980
3207
  await fork.dispose();
2981
3208
  }
2982
3209
  }
2983
- function extractUsage(result) {
3210
+ function extractUsage2(result) {
2984
3211
  if (typeof result !== "object" || result === null) {
2985
3212
  return { inputTokens: 0, outputTokens: 0 };
2986
3213
  }
@@ -3612,309 +3839,103 @@ async function submit(internal) {
3612
3839
  });
3613
3840
  }
3614
3841
  const release = await acquireSlot();
3615
- void (async () => {
3616
- try {
3617
- await checkCancelRequestedAt(resolvedId, aborter);
3618
- if (aborter.signal.aborted) {
3619
- const cancelledAt = Date.now();
3620
- await transition(resolvedId, "cancelled", { cancelledAt });
3621
- emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
3622
- return;
3623
- }
3624
- const startedAt = Date.now();
3625
- await transition(resolvedId, "running", { startedAt });
3626
- emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
3627
- await runWorkAndFinalize(resolvedId, aborter, internal.work);
3628
- } finally {
3629
- release();
3630
- state.aborters.delete(resolvedId);
3631
- }
3632
- })();
3633
- return queuedHandle;
3634
- }
3635
- async function list(filter = {}) {
3636
- return state.store.list(filter);
3637
- }
3638
- async function get(id) {
3639
- if (!isValidTaskId(id, true)) return void 0;
3640
- return state.store.get(id);
3641
- }
3642
- async function cancel(id, reason) {
3643
- if (!isValidTaskId(id, true)) return { cancelled: false, alreadyTerminal: false };
3644
- const handle = await state.store.get(id);
3645
- if (handle === void 0) return { cancelled: false, alreadyTerminal: false };
3646
- if (handle.state === "finished" || handle.state === "error" || handle.state === "cancelled") {
3647
- return { cancelled: false, alreadyTerminal: true };
3648
- }
3649
- const span = startTaskCancelSpan({
3650
- taskId: id,
3651
- ...reason !== void 0 ? { reason } : {},
3652
- via: "api"
3653
- });
3654
- try {
3655
- return await cancelInternal(id, handle.state, reason);
3656
- } finally {
3657
- span.end();
3658
- }
3659
- }
3660
- async function cancelInternal(id, currentState, reason) {
3661
- if (currentState === "queued") {
3662
- const cancelledAt = Date.now();
3663
- await transition(id, "cancelled", { cancelledAt });
3664
- emitToSubscribers(id, {
3665
- type: "cancelled",
3666
- taskId: id,
3667
- cancelledAt,
3668
- ...reason !== void 0 ? { reason } : {}
3669
- });
3670
- state.aborters.delete(id);
3671
- return { cancelled: true, alreadyTerminal: false };
3672
- }
3673
- const aborter = state.aborters.get(id);
3674
- if (aborter !== void 0) aborter.abort(reason ?? "cancelled");
3675
- return { cancelled: true, alreadyTerminal: false };
3676
- }
3677
- async function evictNow(now = Date.now()) {
3678
- return state.store.evictTerminalOlderThan(now - state.retentionMs);
3679
- }
3680
- var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state, subscribe;
3681
- var init_registry = __esm({
3682
- "src/internal/task/registry.ts"() {
3683
- init_errors();
3684
- init_task();
3685
- init_async_semaphore();
3686
- init_ring_buffer();
3687
- init_store();
3688
- init_subscribe();
3689
- init_telemetry();
3690
- DEFAULT_CONCURRENCY = 8;
3691
- DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
3692
- EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
3693
- RING_CAP = 64;
3694
- reentryAls = new AsyncLocalStorage();
3695
- state = buildState({});
3696
- subscribe = buildSubscribe({
3697
- getBuffer: (id) => state.buffers.get(id),
3698
- getOrCreateSubscriberSet: (id) => {
3699
- let subs = state.subscribers.get(id);
3700
- if (subs === void 0) {
3701
- subs = /* @__PURE__ */ new Set();
3702
- state.subscribers.set(id, subs);
3703
- }
3704
- return subs;
3705
- },
3706
- removeSubscriber: (id, cb) => {
3707
- const set = state.subscribers.get(id);
3708
- set?.delete(cb);
3709
- if (set !== void 0 && set.size === 0) state.subscribers.delete(id);
3710
- }
3711
- });
3712
- }
3713
- });
3714
- function toJsonSchema(schema, options = { unrepresentable: "any" }) {
3715
- return toJSONSchema(schema, options);
3716
- }
3717
- var init_to_json_schema = __esm({
3718
- "src/internal/zod/to-json-schema.ts"() {
3719
- }
3720
- });
3721
- function requireZod() {
3722
- if (cachedZ !== void 0) return cachedZ;
3723
- const r = createRequire(import.meta.url);
3724
- let mod;
3725
- try {
3726
- mod = r("zod");
3727
- } catch (cause) {
3728
- throw new ConfigurationError(
3729
- 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
3730
- { code: "zod_not_installed", cause }
3731
- );
3732
- }
3733
- cachedZ = mod.z ?? mod;
3734
- return cachedZ;
3735
- }
3736
- function makeOutputTool(jsonSchema, onCapture) {
3737
- return {
3738
- name: "output",
3739
- description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
3740
- inputSchema: jsonSchema,
3741
- handler: (input) => {
3742
- const out = onCapture(input);
3743
- if (typeof out === "string") return out;
3744
- if (out instanceof Promise) return out;
3745
- return "";
3746
- }
3747
- };
3748
- }
3749
- function buildTransientAgentOptions(params) {
3750
- return {
3751
- model: params.model,
3752
- local: params.local,
3753
- tools: [params.outputTool],
3754
- systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
3755
- ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
3756
- ...params.providers !== void 0 ? { providers: params.providers } : {}
3757
- };
3758
- }
3759
- function extractUsage2(result) {
3760
- const u = result.usage;
3761
- if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
3762
- return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
3763
- }
3764
- function buildToolPrompt(prompt) {
3765
- return `${prompt}
3766
-
3767
- Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
3768
- }
3769
- function setupStructuredOutput(schema, maxRetries) {
3770
- const z8 = requireZod();
3771
- const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
3772
- return {
3773
- z: z8,
3774
- jsonSchema,
3775
- maxRetries: maxRetries ?? 1,
3776
- initialUsage: { inputTokens: 0, outputTokens: 0 }
3777
- };
3778
- }
3779
- async function disposeAndDeleteTransient(agent, deletor) {
3780
- await agent.dispose();
3781
- try {
3782
- await deletor(agent.agentId);
3783
- } catch {
3784
- }
3785
- }
3786
- var cachedZ;
3787
- var init_structured_output_helpers = __esm({
3788
- "src/internal/structured-output-helpers.ts"() {
3789
- init_errors();
3790
- init_to_json_schema();
3791
- }
3792
- });
3793
-
3794
- // src/generate-object.ts
3795
- var generate_object_exports = {};
3796
- __export(generate_object_exports, {
3797
- GenerateObjectError: () => GenerateObjectError,
3798
- generateObjectImpl: () => generateObjectImpl
3799
- });
3800
- function salvagePartial(schema, raw) {
3801
- if (typeof raw !== "object" || raw === null) return raw;
3802
- const shape = schema.shape;
3803
- if (shape === void 0 || typeof shape !== "object") return raw;
3804
- const rawObj = raw;
3805
- const out = {};
3806
- for (const [key2, fieldSchema] of Object.entries(shape)) {
3807
- if (typeof fieldSchema?.safeParse !== "function") continue;
3808
- const parsed = fieldSchema.safeParse(rawObj[key2]);
3809
- if (parsed.success) out[key2] = parsed.data;
3810
- }
3811
- return out;
3812
- }
3813
- async function generateObjectImpl(options, deps) {
3814
- const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
3815
- options.schema,
3816
- options.maxRetries
3817
- );
3818
- let capturedRaw;
3819
- let lastUsage = initialUsage;
3820
- const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
3821
- class CaptureSentinel extends Error {
3822
- constructor(captured) {
3823
- super("generate-object-capture");
3824
- this.captured = captured;
3825
- }
3826
- captured;
3827
- [sentinel] = true;
3828
- }
3829
- const outputTool = makeOutputTool(jsonSchema, (input) => {
3830
- if (capturedRaw === void 0) {
3831
- capturedRaw = input;
3832
- }
3833
- throw new CaptureSentinel(input);
3834
- });
3835
- const agentOptions = buildTransientAgentOptions({
3836
- model: options.model,
3837
- local: options.local,
3838
- outputTool,
3839
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
3840
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
3841
- ...options.providers !== void 0 ? { providers: options.providers } : {}
3842
- });
3843
- const agent = await deps.create(agentOptions);
3844
- try {
3845
- const userMessage = buildToolPrompt(options.prompt);
3846
- let lastParseError;
3847
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
3848
- capturedRaw = void 0;
3849
- const run = await agent.send(userMessage);
3850
- const result = await run.wait();
3851
- lastUsage = extractUsage2(result);
3852
- if (capturedRaw === void 0) {
3853
- if (result.status === "error" && result.error !== void 0) {
3854
- throw new GenerateObjectError(
3855
- "no_tool_call",
3856
- `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
3857
- result.error
3858
- );
3859
- }
3860
- if (attempt === maxRetries) {
3861
- throw new GenerateObjectError(
3862
- "no_tool_call",
3863
- "The model returned text instead of calling the `output` tool."
3864
- );
3865
- }
3866
- continue;
3867
- }
3868
- const parsed = options.schema.safeParse(capturedRaw);
3869
- if (parsed.success) {
3870
- return {
3871
- object: parsed.data,
3872
- raw: capturedRaw,
3873
- usage: lastUsage,
3874
- finishReason: "tool_use"
3875
- };
3876
- }
3877
- lastParseError = parsed.error;
3878
- }
3879
- if (options.errorStrategy === "return-raw") {
3880
- return {
3881
- object: capturedRaw,
3882
- raw: capturedRaw,
3883
- usage: lastUsage,
3884
- finishReason: "tool_use"
3885
- };
3886
- }
3887
- if (options.errorStrategy === "return-partial") {
3888
- return {
3889
- object: salvagePartial(options.schema, capturedRaw),
3890
- raw: capturedRaw,
3891
- usage: lastUsage,
3892
- finishReason: "tool_use"
3893
- };
3842
+ void (async () => {
3843
+ try {
3844
+ await checkCancelRequestedAt(resolvedId, aborter);
3845
+ if (aborter.signal.aborted) {
3846
+ const cancelledAt = Date.now();
3847
+ await transition(resolvedId, "cancelled", { cancelledAt });
3848
+ emitToSubscribers(resolvedId, { type: "cancelled", taskId: resolvedId, cancelledAt });
3849
+ return;
3850
+ }
3851
+ const startedAt = Date.now();
3852
+ await transition(resolvedId, "running", { startedAt });
3853
+ emitToSubscribers(resolvedId, { type: "started", taskId: resolvedId, startedAt });
3854
+ await runWorkAndFinalize(resolvedId, aborter, internal.work);
3855
+ } finally {
3856
+ release();
3857
+ state.aborters.delete(resolvedId);
3894
3858
  }
3895
- throw new GenerateObjectError(
3896
- "parse_failed",
3897
- "Schema parse failed after all retries.",
3898
- lastParseError
3899
- );
3859
+ })();
3860
+ return queuedHandle;
3861
+ }
3862
+ async function list(filter = {}) {
3863
+ return state.store.list(filter);
3864
+ }
3865
+ async function get(id) {
3866
+ if (!isValidTaskId(id, true)) return void 0;
3867
+ return state.store.get(id);
3868
+ }
3869
+ async function cancel(id, reason) {
3870
+ if (!isValidTaskId(id, true)) return { cancelled: false, alreadyTerminal: false };
3871
+ const handle = await state.store.get(id);
3872
+ if (handle === void 0) return { cancelled: false, alreadyTerminal: false };
3873
+ if (handle.state === "finished" || handle.state === "error" || handle.state === "cancelled") {
3874
+ return { cancelled: false, alreadyTerminal: true };
3875
+ }
3876
+ const span = startTaskCancelSpan({
3877
+ taskId: id,
3878
+ ...reason !== void 0 ? { reason } : {},
3879
+ via: "api"
3880
+ });
3881
+ try {
3882
+ return await cancelInternal(id, handle.state, reason);
3900
3883
  } finally {
3901
- await disposeAndDeleteTransient(agent, deps.delete);
3884
+ span.end();
3902
3885
  }
3903
3886
  }
3904
- var GenerateObjectError;
3905
- var init_generate_object = __esm({
3906
- "src/generate-object.ts"() {
3907
- init_structured_output_helpers();
3908
- GenerateObjectError = class extends Error {
3909
- name = "GenerateObjectError";
3910
- code;
3911
- cause;
3912
- constructor(code, message, cause) {
3913
- super(message);
3914
- this.code = code;
3915
- if (cause !== void 0) this.cause = cause;
3887
+ async function cancelInternal(id, currentState, reason) {
3888
+ if (currentState === "queued") {
3889
+ const cancelledAt = Date.now();
3890
+ await transition(id, "cancelled", { cancelledAt });
3891
+ emitToSubscribers(id, {
3892
+ type: "cancelled",
3893
+ taskId: id,
3894
+ cancelledAt,
3895
+ ...reason !== void 0 ? { reason } : {}
3896
+ });
3897
+ state.aborters.delete(id);
3898
+ return { cancelled: true, alreadyTerminal: false };
3899
+ }
3900
+ const aborter = state.aborters.get(id);
3901
+ if (aborter !== void 0) aborter.abort(reason ?? "cancelled");
3902
+ return { cancelled: true, alreadyTerminal: false };
3903
+ }
3904
+ async function evictNow(now = Date.now()) {
3905
+ return state.store.evictTerminalOlderThan(now - state.retentionMs);
3906
+ }
3907
+ var DEFAULT_CONCURRENCY, DEFAULT_RETENTION_MS, EVICTION_INTERVAL_MS, RING_CAP, reentryAls, state, subscribe;
3908
+ var init_registry = __esm({
3909
+ "src/internal/task/registry.ts"() {
3910
+ init_errors();
3911
+ init_task();
3912
+ init_async_semaphore();
3913
+ init_ring_buffer();
3914
+ init_store();
3915
+ init_subscribe();
3916
+ init_telemetry();
3917
+ DEFAULT_CONCURRENCY = 8;
3918
+ DEFAULT_RETENTION_MS = 60 * 60 * 1e3;
3919
+ EVICTION_INTERVAL_MS = 5 * 60 * 1e3;
3920
+ RING_CAP = 64;
3921
+ reentryAls = new AsyncLocalStorage();
3922
+ state = buildState({});
3923
+ subscribe = buildSubscribe({
3924
+ getBuffer: (id) => state.buffers.get(id),
3925
+ getOrCreateSubscriberSet: (id) => {
3926
+ let subs = state.subscribers.get(id);
3927
+ if (subs === void 0) {
3928
+ subs = /* @__PURE__ */ new Set();
3929
+ state.subscribers.set(id, subs);
3930
+ }
3931
+ return subs;
3932
+ },
3933
+ removeSubscriber: (id, cb) => {
3934
+ const set = state.subscribers.get(id);
3935
+ set?.delete(cb);
3936
+ if (set !== void 0 && set.size === 0) state.subscribers.delete(id);
3916
3937
  }
3917
- };
3938
+ });
3918
3939
  }
3919
3940
  });
3920
3941
 
@@ -3972,7 +3993,7 @@ async function* streamObjectImpl(options, deps) {
3972
3993
  }
3973
3994
  }
3974
3995
  const result = await run.wait();
3975
- lastUsage = extractUsage2(result);
3996
+ lastUsage = extractUsage(result);
3976
3997
  if (capturedRaw === void 0) {
3977
3998
  if (result.status === "error" && result.error !== void 0) {
3978
3999
  throw new StreamObjectError(
@@ -4724,7 +4745,10 @@ async function runAgentStep(step, input, ctx) {
4724
4745
  };
4725
4746
  }
4726
4747
  const exec = async () => {
4727
- const run = await step.agent.send(prompt);
4748
+ const run = await step.agent.send(
4749
+ prompt,
4750
+ step.origin !== void 0 ? { origin: step.origin } : void 0
4751
+ );
4728
4752
  const result = await run.wait();
4729
4753
  if (result.status === "finished") {
4730
4754
  return result.result ?? "";
@@ -5496,6 +5520,7 @@ var AgentBuilder = class {
5496
5520
  constructor(deps) {
5497
5521
  this.deps = deps;
5498
5522
  }
5523
+ /** SE8 — accepts a bare-string id shorthand (`"openai/gpt-4o-mini"`) or a {@link ModelSelection}. */
5499
5524
  model(m) {
5500
5525
  this.opts.model = m;
5501
5526
  return this;
@@ -5853,13 +5878,87 @@ function isLocalAgentId(id) {
5853
5878
  return id.startsWith(PREFIX.localAgent);
5854
5879
  }
5855
5880
 
5881
+ // src/internal/runtime/config/default-model.ts
5882
+ var DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
5883
+
5884
+ // src/agent-generate.ts
5885
+ async function agentGenerate(agent, agentModel, agentApiKey, agentLocal, input, options) {
5886
+ const { output, maxRetries, errorStrategy, ...sendOptions } = options;
5887
+ const run = await agent.send(input, sendOptions);
5888
+ const result = await run.wait();
5889
+ const { generateObjectImpl: generateObjectImpl2, GenerateObjectError: GenerateObjectError2 } = await Promise.resolve().then(() => (init_generate_object(), generate_object_exports));
5890
+ const answer = structurableAnswerOrThrow(result, GenerateObjectError2);
5891
+ const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
5892
+ const facade = getAgentFacade2();
5893
+ const structured = await generateObjectImpl2(
5894
+ {
5895
+ prompt: answer,
5896
+ schema: output,
5897
+ // `agentModel` arrives already normalized (`this.model` passed through
5898
+ // `normalizeModel` in the LocalAgent/CloudAgent constructor), so the widened
5899
+ // `string | ModelSelection` field only ever receives a `ModelSelection` here.
5900
+ model: agentModel ?? { id: DEFAULT_AGENTIC_MODEL_ID },
5901
+ // `local` is required to keep the transient structuring agent local-only;
5902
+ // default to the process cwd when the agent had no explicit local config.
5903
+ local: agentLocal ?? { cwd: process.cwd() },
5904
+ ...agentApiKey !== void 0 ? { apiKey: agentApiKey } : {},
5905
+ ...maxRetries !== void 0 ? { maxRetries } : {},
5906
+ ...errorStrategy !== void 0 ? { errorStrategy } : {}
5907
+ },
5908
+ {
5909
+ create: (opts) => facade.create(opts),
5910
+ delete: (agentId) => facade.delete(agentId)
5911
+ }
5912
+ );
5913
+ return {
5914
+ object: structured.object,
5915
+ result,
5916
+ raw: structured.raw,
5917
+ usage: structured.usage
5918
+ };
5919
+ }
5920
+ function structurableAnswerOrThrow(result, GenerateObjectError2) {
5921
+ if (result.status === "error") {
5922
+ throw new GenerateObjectError2(
5923
+ "no_tool_call",
5924
+ `Agent run failed before an answer could be structured: ${result.error?.message ?? "unknown error"} [${result.error?.code ?? "?"}]`,
5925
+ result.error
5926
+ );
5927
+ }
5928
+ if (result.status === "cancelled") {
5929
+ throw new GenerateObjectError2(
5930
+ "no_tool_call",
5931
+ "Agent run was cancelled before an answer could be structured."
5932
+ );
5933
+ }
5934
+ const answer = result.result;
5935
+ if (answer === void 0 || answer.length === 0) {
5936
+ throw new GenerateObjectError2(
5937
+ "no_tool_call",
5938
+ "The tool loop finished with no text answer (tool-only completion) \u2014 there is nothing to structure."
5939
+ );
5940
+ }
5941
+ return answer;
5942
+ }
5943
+
5856
5944
  // src/internal/runtime/cloud/cloud-agent.ts
5857
5945
  init_errors();
5858
5946
  init_cwd_mutex();
5859
5947
  init_path_guard();
5860
5948
 
5861
- // src/internal/runtime/config/default-model.ts
5862
- var DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
5949
+ // src/internal/runtime/model-selection.ts
5950
+ init_errors();
5951
+ function normalizeModel(m) {
5952
+ if (m === void 0 || typeof m !== "string") return m;
5953
+ const id = m.trim();
5954
+ if (id.length === 0) {
5955
+ throw new ConfigurationError(
5956
+ 'model must be a non-empty "provider/model" id string or a ModelSelection object',
5957
+ { code: "invalid_model_selection" }
5958
+ );
5959
+ }
5960
+ return { id };
5961
+ }
5863
5962
 
5864
5963
  // src/internal/runtime/registry/agent-registry-store.ts
5865
5964
  init_cwd_mutex();
@@ -5936,7 +6035,10 @@ var REGISTRY_RELATIVE_PATH = join(".theokit", "agents", "registry.json");
5936
6035
  function stripSecretsFromOptions(options) {
5937
6036
  return assignDefined({
5938
6037
  name: options.name,
5939
- model: options.model !== void 0 ? { id: options.model.id } : void 0,
6038
+ model: (() => {
6039
+ const m = normalizeModel(options.model);
6040
+ return m !== void 0 ? { id: m.id } : void 0;
6041
+ })(),
5940
6042
  systemPrompt: typeof options.systemPrompt === "string" ? options.systemPrompt : void 0,
5941
6043
  local: serializeLocal(options.local),
5942
6044
  cloud: serializeCloud(options.cloud),
@@ -6221,7 +6323,8 @@ function serializeCloudAgentConfig(options) {
6221
6323
  cloud: serializeCloud2(options.cloud)
6222
6324
  };
6223
6325
  if (typeof options.agentId === "string") payload.agentId = options.agentId;
6224
- if (options.model !== void 0) payload.model = { id: options.model.id };
6326
+ const cfgModel = normalizeModel(options.model);
6327
+ if (cfgModel !== void 0) payload.model = { id: cfgModel.id };
6225
6328
  if (typeof options.systemPrompt === "string") payload.systemPrompt = options.systemPrompt;
6226
6329
  const skills = serializeSkills(options.skills);
6227
6330
  if (skills !== void 0) payload.skills = skills;
@@ -7026,6 +7129,7 @@ function applyScriptMetrics(base, script) {
7026
7129
  if (script.cost !== void 0) base.cost = script.cost;
7027
7130
  if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
7028
7131
  if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
7132
+ if (script.origin !== void 0) base.origin = script.origin;
7029
7133
  }
7030
7134
 
7031
7135
  // src/internal/runtime/cloud/cloud-run.ts
@@ -7381,7 +7485,7 @@ var CloudAgent = class {
7381
7485
  disposed = false;
7382
7486
  constructor(options, providedAgentId) {
7383
7487
  this.agentId = providedAgentId ?? options.agentId ?? generateCloudAgentId();
7384
- this.model = options.model;
7488
+ this.model = normalizeModel(options.model);
7385
7489
  this.options = options;
7386
7490
  this.cloudPayload = serializeCloudAgentConfig({ ...options, agentId: this.agentId });
7387
7491
  const repoUrls = (options.cloud?.repos ?? []).map((repo) => repo.url);
@@ -7411,6 +7515,17 @@ var CloudAgent = class {
7411
7515
  const apiKey = resolveApiKey(this.options.apiKey);
7412
7516
  return isFixtureApiKey(apiKey) && getConfiguredBaseUrl() === void 0;
7413
7517
  }
7518
+ // SE9 — integrated structured output; delegates to the shared helper.
7519
+ generate(message, options) {
7520
+ return agentGenerate(
7521
+ this,
7522
+ this.model,
7523
+ this.options.apiKey,
7524
+ this.options.local,
7525
+ message,
7526
+ options
7527
+ );
7528
+ }
7414
7529
  async send(message, options = {}) {
7415
7530
  if (options.tools !== void 0 && options.tools.length > 0) {
7416
7531
  throw new ConfigurationError(
@@ -7441,7 +7556,7 @@ var CloudAgent = class {
7441
7556
  });
7442
7557
  }
7443
7558
  async sendLocked(message, options) {
7444
- const overrideModel = options.model;
7559
+ const overrideModel = normalizeModel(options.model);
7445
7560
  if (overrideModel !== void 0) {
7446
7561
  this.model = overrideModel;
7447
7562
  updateRegisteredAgent(this.agentId, { model: overrideModel });
@@ -8358,18 +8473,18 @@ var ALL_ADAPTERS = [
8358
8473
  arizeAdapter,
8359
8474
  braintrustAdapter
8360
8475
  ];
8361
- var registered = /* @__PURE__ */ new Set();
8476
+ var registered2 = /* @__PURE__ */ new Set();
8362
8477
  function tryAutoRegisterAdapters(settings) {
8363
8478
  if (settings?.enabled !== true) return;
8364
8479
  if (settings.autoDetect === false) return;
8365
8480
  const disabled = new Set(settings.disable ?? []);
8366
8481
  for (const adapter of ALL_ADAPTERS) {
8367
- if (registered.has(adapter.moduleName)) continue;
8482
+ if (registered2.has(adapter.moduleName)) continue;
8368
8483
  if (disabled.has(adapter.displayName.toLowerCase())) continue;
8369
8484
  if (!adapter.detect()) continue;
8370
8485
  try {
8371
8486
  adapter.register();
8372
- registered.add(adapter.moduleName);
8487
+ registered2.add(adapter.moduleName);
8373
8488
  process.stderr.write(`[theokit-sdk] telemetry: ${adapter.displayName} auto-instrumented.
8374
8489
  `);
8375
8490
  } catch (cause) {
@@ -8899,6 +9014,26 @@ function paginate(items, opts) {
8899
9014
  return items.slice(start, end);
8900
9015
  }
8901
9016
 
9017
+ // src/internal/persistence/session-meta.ts
9018
+ function applyMetaPatch(current, patch) {
9019
+ const next = {};
9020
+ if (current.title !== void 0) next.title = current.title;
9021
+ if (current.tag !== void 0) next.tag = current.tag;
9022
+ if (patch.title === null) delete next.title;
9023
+ else if (patch.title !== void 0) next.title = patch.title;
9024
+ if (patch.tag === null) delete next.tag;
9025
+ else if (patch.tag !== void 0) next.tag = patch.tag;
9026
+ return next;
9027
+ }
9028
+ function coerceSessionMeta(raw) {
9029
+ if (typeof raw !== "object" || raw === null) return void 0;
9030
+ const obj = raw;
9031
+ const meta = {};
9032
+ if (typeof obj.title === "string") meta.title = obj.title;
9033
+ if (typeof obj.tag === "string") meta.tag = obj.tag;
9034
+ return meta.title === void 0 && meta.tag === void 0 ? void 0 : meta;
9035
+ }
9036
+
8902
9037
  // src/internal/persistence/conversation-storage-fs.ts
8903
9038
  var FileSystemConversationStorage = class {
8904
9039
  #root;
@@ -8949,6 +9084,37 @@ var FileSystemConversationStorage = class {
8949
9084
  async compact(conversationId, maxTurns) {
8950
9085
  await compactSessionFile(this.#root, conversationId, maxTurns);
8951
9086
  }
9087
+ // SE4 — session metadata persisted as a per-conversation sidecar
9088
+ // `<root>/.theokit/agents/<safeId>/session.json` (same sanitized perimeter as
9089
+ // the transcript). Kept separate from messages.jsonl so a title/tag write does
9090
+ // not rewrite the append-only log.
9091
+ #metaPath(conversationId) {
9092
+ const safe2 = sanitizeIdentifier(conversationId, { maxLen: 128 });
9093
+ return safePathJoin(this.#root, ".theokit", "agents", safe2, "session.json");
9094
+ }
9095
+ async getSessionMeta(conversationId) {
9096
+ try {
9097
+ const raw = await readFile(this.#metaPath(conversationId), "utf8");
9098
+ return coerceSessionMeta(JSON.parse(raw));
9099
+ } catch (cause) {
9100
+ if (cause.code === "ENOENT") return void 0;
9101
+ throw cause;
9102
+ }
9103
+ }
9104
+ async setSessionMeta(conversationId, patch) {
9105
+ const metaPath = this.#metaPath(conversationId);
9106
+ await mkdir(dirname(metaPath), { recursive: true });
9107
+ await withFileLock(metaPath, async () => {
9108
+ let current = {};
9109
+ try {
9110
+ current = coerceSessionMeta(JSON.parse(await readFile(metaPath, "utf8"))) ?? {};
9111
+ } catch (cause) {
9112
+ if (cause.code !== "ENOENT") throw cause;
9113
+ }
9114
+ const next = applyMetaPatch(current, patch);
9115
+ await writeFile(metaPath, redactSecrets(JSON.stringify(next)), "utf8");
9116
+ });
9117
+ }
8952
9118
  async dispose() {
8953
9119
  }
8954
9120
  };
@@ -10800,23 +10966,27 @@ function tryParseSkill(raw, fallbackName, source, options) {
10800
10966
 
10801
10967
  // src/internal/runtime/skills/skills-manager.ts
10802
10968
  var SkillsManager = class {
10803
- constructor(cwd, _enabled, settingSourcesIncludeProject) {
10969
+ constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
10804
10970
  this.cwd = cwd;
10805
10971
  this.settingSourcesIncludeProject = settingSourcesIncludeProject;
10972
+ this.skillsDir = skillsDir;
10973
+ this.inline = inline;
10806
10974
  }
10807
10975
  cwd;
10808
10976
  settingSourcesIncludeProject;
10977
+ skillsDir;
10978
+ inline;
10809
10979
  skills = [];
10810
10980
  async initialize() {
10811
10981
  if (!this.settingSourcesIncludeProject) {
10812
- this.skills = [];
10982
+ this.skills = this.mergeInline([]);
10813
10983
  return;
10814
10984
  }
10815
10985
  await this.refresh();
10816
10986
  }
10817
10987
  async refresh() {
10818
- const skillsRoot = join(this.cwd, ".theokit", "skills");
10819
- this.skills = await discoverSkills(skillsRoot, {
10988
+ const skillsRoot = this.skillsDir ?? join(this.cwd, ".theokit", "skills");
10989
+ const discovered = await discoverSkills(skillsRoot, {
10820
10990
  onInvalidSkill: (info) => {
10821
10991
  process.stderr.write(
10822
10992
  `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
@@ -10824,6 +10994,13 @@ var SkillsManager = class {
10824
10994
  );
10825
10995
  }
10826
10996
  });
10997
+ this.skills = this.mergeInline(discovered);
10998
+ }
10999
+ /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
11000
+ mergeInline(discovered) {
11001
+ if (this.inline === void 0 || this.inline.length === 0) return discovered;
11002
+ const inlineNames = new Set(this.inline.map((s) => s.name));
11003
+ return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
10827
11004
  }
10828
11005
  list() {
10829
11006
  return Promise.resolve(this.skills);
@@ -10859,7 +11036,7 @@ function bootstrapSubmanagers(args) {
10859
11036
  const providerCount = (args.options.providers?.routes?.length ?? 0) + enabledPluginNames(args.options.plugins).length;
10860
11037
  if (providerCount > 0 || args.options.providers !== void 0) {
10861
11038
  out.providers = new ProvidersManagerImpl(
10862
- args.options.model,
11039
+ normalizeModel(args.options.model),
10863
11040
  args.options.providers,
10864
11041
  args.options.plugins
10865
11042
  );
@@ -10868,7 +11045,10 @@ function bootstrapSubmanagers(args) {
10868
11045
  out.skillsManager = new SkillsManager(
10869
11046
  args.workspaceCwd,
10870
11047
  args.options.skills?.enabled,
10871
- args.settingSourcesIncludeProject
11048
+ args.settingSourcesIncludeProject,
11049
+ // M22 — custom skills directory + inline (code-defined) skills.
11050
+ args.options.skills?.skillsDir,
11051
+ args.options.skills?.inline
10872
11052
  );
10873
11053
  const localSkills = out.skillsManager;
10874
11054
  out.skills = { list: () => localSkills.list() };
@@ -10926,6 +11106,7 @@ function createLocalRun(options) {
10926
11106
  projectMcpServers: options.projectMcpServers,
10927
11107
  ...options.persistMemoryFact !== void 0 ? { persistMemoryFact: options.persistMemoryFact } : {}
10928
11108
  });
11109
+ if (options.sendOptions.origin !== void 0) script.origin = options.sendOptions.origin;
10929
11110
  const handle = new LocalRun({
10930
11111
  id,
10931
11112
  agentId: options.agentId,
@@ -11574,6 +11755,15 @@ async function emitReasoningDeltaCallback(inputs, text) {
11574
11755
  );
11575
11756
  }
11576
11757
 
11758
+ // src/types/run-events.ts
11759
+ function emitRunEvent(sink, event) {
11760
+ if (sink === void 0) return;
11761
+ try {
11762
+ sink(event);
11763
+ } catch {
11764
+ }
11765
+ }
11766
+
11577
11767
  // src/internal/agent-loop/tool-dispatch.ts
11578
11768
  init_async_local_storage();
11579
11769
 
@@ -11671,6 +11861,22 @@ function coerceArgsToSchema(args, schema) {
11671
11861
  return { value: out, changed };
11672
11862
  }
11673
11863
 
11864
+ // src/tool-error.ts
11865
+ init_errors();
11866
+ var ToolError = class extends TheokitAgentError {
11867
+ name = "ToolError";
11868
+ /** The error content surfaced to the model: a string, or text/image blocks. */
11869
+ content;
11870
+ constructor(content, options = {}) {
11871
+ super(renderToolErrorMessage(content), { ...options, isRetryable: false });
11872
+ this.content = content;
11873
+ }
11874
+ };
11875
+ function renderToolErrorMessage(content) {
11876
+ if (typeof content === "string") return content;
11877
+ return content.map((block) => block.type === "text" ? block.text : `[${block.source.media_type} image]`).join("\n");
11878
+ }
11879
+
11674
11880
  // src/internal/runtime/tools/shell-tool.ts
11675
11881
  async function runShell(options) {
11676
11882
  if (options.sandbox === true && isObviouslyUnsafe(options.command)) {
@@ -11724,9 +11930,13 @@ async function runHandlerTool(kind, handler, call, signal, context) {
11724
11930
  return { stdout: "", stderr: `${kind} tool ${call.name} has no handler`, exitCode: 127 };
11725
11931
  }
11726
11932
  try {
11727
- const stdout = await handler(call.input, { signal, context });
11728
- return { stdout, stderr: "", exitCode: 0 };
11933
+ const out = await handler(call.input, { signal, context });
11934
+ if (typeof out !== "string") return { stdout: "", stderr: "", exitCode: 0, content: out };
11935
+ return { stdout: out, stderr: "", exitCode: 0 };
11729
11936
  } catch (cause) {
11937
+ if (cause instanceof ToolError) {
11938
+ return { stdout: "", stderr: cause.message, exitCode: 1, content: cause.content };
11939
+ }
11730
11940
  const message = cause instanceof Error ? cause.message : String(cause);
11731
11941
  return { stdout: "", stderr: message, exitCode: 1 };
11732
11942
  }
@@ -11845,6 +12055,11 @@ async function dispatchSingleCall(inputs, tools, call, events, parentSpan) {
11845
12055
  toolSpan?.end();
11846
12056
  return fileVeto;
11847
12057
  }
12058
+ emitRunEvent(inputs.runEventSink, {
12059
+ type: "tool_progress",
12060
+ toolName: workingCall.name,
12061
+ toolCallId: callId
12062
+ });
11848
12063
  const result = await runToolWithLifecycle(inputs, resolved, workingCall, callId);
11849
12064
  await inputs.pluginManager?.runPostToolCallHooks({
11850
12065
  name: workingCall.name,
@@ -11871,6 +12086,13 @@ function applyRepairAndExtractCall(tools, call) {
11871
12086
  function vetoFromForkWhitelist(inputs, call, callId, events) {
11872
12087
  const whitelistDecision = checkToolWhitelist(call.name);
11873
12088
  if (whitelistDecision.allowed) return void 0;
12089
+ emitRunEvent(inputs.runEventSink, {
12090
+ type: "permission_denied",
12091
+ toolName: call.name,
12092
+ toolCallId: callId,
12093
+ source: "fork_whitelist",
12094
+ message: whitelistDecision.reason ?? "tool not available in fork"
12095
+ });
11874
12096
  events.push(buildToolUseRunning(inputs, callId, call));
11875
12097
  events.push(
11876
12098
  buildToolUseCompleted(inputs, callId, call, {
@@ -11907,6 +12129,13 @@ async function vetoFromPluginPreHook(inputs, call, callId, events) {
11907
12129
  runId: inputs.runId
11908
12130
  });
11909
12131
  if (pluginVeto === void 0) return void 0;
12132
+ emitRunEvent(inputs.runEventSink, {
12133
+ type: "permission_denied",
12134
+ toolName: call.name,
12135
+ toolCallId: callId,
12136
+ source: "plugin",
12137
+ message: pluginVeto.message
12138
+ });
11910
12139
  events.push(
11911
12140
  buildToolUseCompleted(inputs, callId, call, {
11912
12141
  stdout: "",
@@ -11929,6 +12158,13 @@ async function vetoFromFileHookPreDecision(inputs, call, callId, events) {
11929
12158
  runId: inputs.runId
11930
12159
  });
11931
12160
  if (!preDecision.blocked) return void 0;
12161
+ emitRunEvent(inputs.runEventSink, {
12162
+ type: "permission_denied",
12163
+ toolName: call.name,
12164
+ toolCallId: callId,
12165
+ source: "file_hook",
12166
+ message: preDecision.reason ?? "blocked by hook"
12167
+ });
11932
12168
  events.push(
11933
12169
  buildToolUseCompleted(inputs, callId, call, {
11934
12170
  stdout: "",
@@ -11972,7 +12208,9 @@ async function runToolWithLifecycle(inputs, resolved, call, callId) {
11972
12208
  await safeEmitToolHook(inputs.onToolEnd, {
11973
12209
  toolName: call.name,
11974
12210
  args: call.input,
11975
- result: result.stdout,
12211
+ // SE7 — a block-returning handler has empty `stdout`; surface its structured
12212
+ // content to the hook instead of an empty string.
12213
+ result: result.content !== void 0 ? result.content : result.stdout,
11976
12214
  conversationId: inputs.agentId,
11977
12215
  callId,
11978
12216
  durationMs
@@ -11994,7 +12232,10 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
11994
12232
  output: {
11995
12233
  stdout: result.stdout,
11996
12234
  stderr: result.stderr,
11997
- exitCode: result.exitCode ?? 0
12235
+ exitCode: result.exitCode ?? 0,
12236
+ // SE7 — structured content (text + image blocks) when the handler
12237
+ // returned/threw blocks; absent for the string path.
12238
+ ...result.content !== void 0 ? { content: result.content } : {}
11998
12239
  },
11999
12240
  agentId: inputs.agentId,
12000
12241
  runId: inputs.runId
@@ -12007,7 +12248,9 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
12007
12248
  return {
12008
12249
  type: "tool_result",
12009
12250
  toolUseId: call.id,
12010
- content: renderToolResult(result),
12251
+ // SE7 — structured content blocks (handler-returned or ToolError-carried)
12252
+ // are authoritative; otherwise the legacy string rendering.
12253
+ content: result.content !== void 0 ? result.content : renderToolResult(result),
12011
12254
  ...result.exitCode !== 0 && result.exitCode !== void 0 ? { isError: true } : {}
12012
12255
  };
12013
12256
  }
@@ -12056,6 +12299,29 @@ function buildToolUseCompleted(inputs, callId, call, result) {
12056
12299
  };
12057
12300
  }
12058
12301
 
12302
+ // src/internal/llm/tool-result-content.ts
12303
+ init_errors();
12304
+ function toBlockToolResultContent(content) {
12305
+ return content;
12306
+ }
12307
+ function toStringToolResultContent(content, providerName) {
12308
+ if (typeof content === "string") return content;
12309
+ if (content.some((block) => block.type === "image")) {
12310
+ throw new ConfigurationError(
12311
+ `provider "${providerName}" does not support image content in tool results`
12312
+ );
12313
+ }
12314
+ return content.filter(
12315
+ (block) => block.type === "text"
12316
+ ).map((block) => block.text).join("\n");
12317
+ }
12318
+ function renderToolResultContentText(content, fn) {
12319
+ if (typeof content === "string") return fn(content);
12320
+ return content.map(
12321
+ (block) => block.type === "text" ? { type: "text", text: fn(block.text) } : block
12322
+ );
12323
+ }
12324
+
12059
12325
  // src/internal/agent-loop/tool-result-guard.ts
12060
12326
  var OPEN = "<untrusted-tool-output>";
12061
12327
  var CLOSE = "</untrusted-tool-output>";
@@ -12081,7 +12347,11 @@ ${CLOSE}`;
12081
12347
  function applyToolResultGuard(parts, opts) {
12082
12348
  if (opts.delimit !== true && opts.redactPii !== true) return parts;
12083
12349
  return parts.map(
12084
- (p) => p.type === "tool_result" ? { ...p, content: guardText(p.content, opts) } : p
12350
+ (p) => (
12351
+ // SE7 — guard the TEXT of a tool result (string or the text blocks of a
12352
+ // structured content); image blocks pass through untouched.
12353
+ p.type === "tool_result" ? { ...p, content: renderToolResultContentText(p.content, (t) => guardText(t, opts)) } : p
12354
+ )
12085
12355
  );
12086
12356
  }
12087
12357
 
@@ -13012,10 +13282,10 @@ function stripVertexPrefix(modelId) {
13012
13282
  }
13013
13283
 
13014
13284
  // src/internal/providers/builtin/index.ts
13015
- var registered2 = false;
13285
+ var registered3 = false;
13016
13286
  function registerBuiltins() {
13017
- if (registered2) return;
13018
- registered2 = true;
13287
+ if (registered3) return;
13288
+ registered3 = true;
13019
13289
  registerProvider(ANTHROPIC);
13020
13290
  registerProvider(OPENAI);
13021
13291
  registerProvider(OPENROUTER);
@@ -13244,7 +13514,9 @@ function toAnthropicWireMessage(message) {
13244
13514
  return {
13245
13515
  type: "tool_result",
13246
13516
  tool_use_id: part.toolUseId,
13247
- content: part.content,
13517
+ // SE7 — this wire is block-capable: strings pass through, structured
13518
+ // text/image blocks are forwarded natively.
13519
+ content: toBlockToolResultContent(part.content),
13248
13520
  ...part.isError === true ? { is_error: true } : {}
13249
13521
  };
13250
13522
  });
@@ -14036,7 +14308,8 @@ function toOllamaMessages(message) {
14036
14308
  if (part.type === "tool_result") {
14037
14309
  out.push({
14038
14310
  role: "tool",
14039
- content: part.content,
14311
+ // SE7 — string-only tool role: text blocks flatten; image fails fast.
14312
+ content: toStringToolResultContent(part.content, "ollama"),
14040
14313
  tool_name: part.toolUseId
14041
14314
  });
14042
14315
  }
@@ -14573,7 +14846,9 @@ function userOrToolMessages(message) {
14573
14846
  out.push({
14574
14847
  role: "tool",
14575
14848
  tool_call_id: part.toolUseId,
14576
- content: part.content
14849
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
14850
+ // image block fails fast (ConfigurationError).
14851
+ content: toStringToolResultContent(part.content, "openai")
14577
14852
  });
14578
14853
  }
14579
14854
  }
@@ -15503,18 +15778,20 @@ function levenshtein(a, b) {
15503
15778
  function createRealLocalRun(options) {
15504
15779
  const { userText, id, startTime } = prepareRunContext(options.message);
15505
15780
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
15506
- const unusedFixtureScript = {
15781
+ const runScript = {
15507
15782
  events: [],
15508
15783
  finalStatus: "running",
15509
15784
  cancellable: false,
15510
- conversation: []
15785
+ conversation: [],
15786
+ // SE3 — carry the turn's provenance so buildResult forwards it onto RunResult.origin.
15787
+ ...options.sendOptions.origin !== void 0 ? { origin: options.sendOptions.origin } : {}
15511
15788
  };
15512
15789
  const handle = new RealLocalRun(
15513
15790
  {
15514
15791
  id,
15515
15792
  agentId: options.agentId,
15516
15793
  model: options.model,
15517
- script: unusedFixtureScript,
15794
+ script: runScript,
15518
15795
  supportedOps: supported,
15519
15796
  startTime
15520
15797
  },
@@ -15626,6 +15903,8 @@ function buildLoopInputs(options, runId, userText) {
15626
15903
  // M7 — forward SendOptions.context to the loop so every tool handler receives
15627
15904
  // it on `ctx.context` (shared run config set once, e.g. projectRoot).
15628
15905
  ...options.sendOptions.context !== void 0 ? { context: options.sendOptions.context } : {},
15906
+ // SE2 — forward the opt-in typed runtime-event sink to the loop.
15907
+ ...options.sendOptions.onRunEvent !== void 0 ? { runEventSink: options.sendOptions.onRunEvent } : {},
15629
15908
  // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
15630
15909
  // can enable them via SendOptions (not only internal AgentLoopInputs).
15631
15910
  ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
@@ -17370,7 +17649,7 @@ function wrapRunWithPostReplyHook(args) {
17370
17649
  async function executeSendLocked(inputs, message, options) {
17371
17650
  if (inputs.disposed) throw new AgentDisposedError(inputs.agentId);
17372
17651
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
17373
- inputs.applyModelOverride(options.model);
17652
+ inputs.applyModelOverride(normalizeModel(options.model));
17374
17653
  const userText = typeof message === "string" ? message : message.text;
17375
17654
  if (inputs.options.onBeforeSend !== void 0) {
17376
17655
  await inputs.options.onBeforeSend({
@@ -17522,7 +17801,7 @@ var LocalAgent = class {
17522
17801
  constructor(options) {
17523
17802
  this.agentId = options.agentId ?? generateLocalAgentId();
17524
17803
  this._telemetry = createTelemetry(options.telemetry);
17525
- this.model = options.model;
17804
+ this.model = normalizeModel(options.model);
17526
17805
  this.options = options;
17527
17806
  this.workspaceCwd = resolveCwd(options.local?.cwd);
17528
17807
  this.conversationStorage = options.conversationStorage;
@@ -17589,6 +17868,11 @@ var LocalAgent = class {
17589
17868
  hooks() {
17590
17869
  return this.hooksExecutor;
17591
17870
  }
17871
+ // SE9 — integrated structured output; delegates to the shared helper.
17872
+ generate(message, options) {
17873
+ const { apiKey, local } = this.options;
17874
+ return agentGenerate(this, this.model, apiKey, local, message, options);
17875
+ }
17592
17876
  async send(message, options = {}) {
17593
17877
  if (options.tools !== void 0 && options.tools.length > 0) {
17594
17878
  validateToolCatalog(options.tools);
@@ -17828,6 +18112,7 @@ function includesSetting(options, source) {
17828
18112
 
17829
18113
  // src/agent-helpers.ts
17830
18114
  async function runCreateUnderSpan(options, span) {
18115
+ options = { ...options, model: normalizeModel(options.model) };
17831
18116
  validateAgentOptions(options);
17832
18117
  validateCloudToolParity(options);
17833
18118
  await guardAgainstIdCollision(options);
@@ -17901,7 +18186,10 @@ async function createLocalAgent(options) {
17901
18186
  const willFlowToProvider = !isFixtureApiKey(apiKey) && !shouldUseRealLocalRuntime(apiKey);
17902
18187
  const shape = validateApiKeyShape(apiKey, {
17903
18188
  strict: willFlowToProvider,
17904
- ...willFlowToProvider ? { provider: providerFromModelId(options.model?.id) } : {}
18189
+ // `options.model` is already normalized by `runCreateUnderSpan`; `normalizeModel`
18190
+ // here is the idempotent narrowing of the widened public type (`{id}` passes
18191
+ // through by reference) — cleaner than an `as` cast.
18192
+ ...willFlowToProvider ? { provider: providerFromModelId(normalizeModel(options.model)?.id) } : {}
17905
18193
  });
17906
18194
  if (shape.malformed) {
17907
18195
  throw new AuthenticationError(shape.message, { code: "malformed_api_key" });
@@ -17967,6 +18255,10 @@ async function rehydrateExistingAgent(agentId, existing, options) {
17967
18255
  ...existing.options,
17968
18256
  ...options,
17969
18257
  ...mergedLocal !== void 0 ? { local: mergedLocal } : {},
18258
+ // SE8 — normalize a caller-supplied bare-string model override at this resume
18259
+ // boundary (Agent.resume never flows through runCreateUnderSpan). Cloud resume
18260
+ // honors it; local resume forces the persisted model below.
18261
+ model: normalizeModel(options.model ?? existing.options.model),
17970
18262
  mcpServers: void 0,
17971
18263
  agentId
17972
18264
  };
@@ -18333,6 +18625,7 @@ async function getOrCreateUncached(agentId, options) {
18333
18625
  }
18334
18626
  setAgentFacade({
18335
18627
  create: (options) => Agent.create(options),
18628
+ delete: (agentId) => Agent.delete(agentId),
18336
18629
  prompt: (message, options) => Agent.prompt(message, options),
18337
18630
  get: (agentId) => Agent.get(agentId),
18338
18631
  resume: (agentId, options) => Agent.resume(agentId, options),
@@ -18770,6 +19063,20 @@ var Budget = class {
18770
19063
  }
18771
19064
  };
18772
19065
 
19066
+ // src/create-skill.ts
19067
+ function createSkill(spec) {
19068
+ if (!spec.name) throw new Error("createSkill: `name` is required.");
19069
+ if (!spec.description) throw new Error("createSkill: `description` is required.");
19070
+ return {
19071
+ name: spec.name,
19072
+ description: spec.description,
19073
+ source: `inline://${spec.name}`,
19074
+ instructions: spec.instructions,
19075
+ ...spec.category !== void 0 ? { category: spec.category } : {},
19076
+ ...spec.dependencies !== void 0 ? { dependencies: spec.dependencies } : {}
19077
+ };
19078
+ }
19079
+
18773
19080
  // src/cron.ts
18774
19081
  init_errors();
18775
19082
 
@@ -19279,6 +19586,8 @@ init_generate_object();
19279
19586
  // src/internal/persistence/conversation-storage-memory.ts
19280
19587
  var InMemoryConversationStorage = class {
19281
19588
  #store = /* @__PURE__ */ new Map();
19589
+ // SE4 — session-level metadata (title/tag), kept beside the transcript.
19590
+ #meta = /* @__PURE__ */ new Map();
19282
19591
  async getMessages(conversationId, opts) {
19283
19592
  const existing = this.#store.get(conversationId);
19284
19593
  return existing === void 0 ? [] : paginate(existing.slice(), opts);
@@ -19307,15 +19616,20 @@ var InMemoryConversationStorage = class {
19307
19616
  }
19308
19617
  async deleteConversation(conversationId) {
19309
19618
  this.#store.delete(conversationId);
19619
+ this.#meta.delete(conversationId);
19310
19620
  }
19311
19621
  async deleteScope(prefix) {
19312
19622
  let n = 0;
19313
19623
  for (const id of [...this.#store.keys()]) {
19314
19624
  if (id.startsWith(prefix)) {
19315
19625
  this.#store.delete(id);
19626
+ this.#meta.delete(id);
19316
19627
  n += 1;
19317
19628
  }
19318
19629
  }
19630
+ for (const id of [...this.#meta.keys()]) {
19631
+ if (id.startsWith(prefix)) this.#meta.delete(id);
19632
+ }
19319
19633
  return n;
19320
19634
  }
19321
19635
  async listConversationIds(opts) {
@@ -19323,8 +19637,17 @@ var InMemoryConversationStorage = class {
19323
19637
  if (opts?.limit !== void 0) return all.slice(0, opts.limit);
19324
19638
  return all;
19325
19639
  }
19640
+ async getSessionMeta(conversationId) {
19641
+ const meta = this.#meta.get(conversationId);
19642
+ return meta === void 0 ? void 0 : { ...meta };
19643
+ }
19644
+ async setSessionMeta(conversationId, patch) {
19645
+ const current = this.#meta.get(conversationId) ?? {};
19646
+ this.#meta.set(conversationId, applyMetaPatch(current, patch));
19647
+ }
19326
19648
  async dispose() {
19327
19649
  this.#store.clear();
19650
+ this.#meta.clear();
19328
19651
  }
19329
19652
  };
19330
19653
 
@@ -20064,6 +20387,21 @@ async function migrateSqliteToLance2(options) {
20064
20387
  }
20065
20388
 
20066
20389
  // src/permission-engine.ts
20390
+ function applyMode(verdict, mode, explicit) {
20391
+ if (verdict === "deny") return "deny";
20392
+ switch (mode) {
20393
+ case "default":
20394
+ return verdict;
20395
+ case "plan":
20396
+ return verdict === "allow" ? "allow" : "deny";
20397
+ case "acceptEdits":
20398
+ if (verdict === "ask") return explicit ? "ask" : "allow";
20399
+ return verdict;
20400
+ // allow stays allow
20401
+ case "bypass":
20402
+ return "allow";
20403
+ }
20404
+ }
20067
20405
  function argMatches(matcher, value) {
20068
20406
  if (typeof matcher === "function") return matcher(value);
20069
20407
  if (value === void 0) return false;
@@ -20084,14 +20422,14 @@ var PermissionEngine = class {
20084
20422
  * argument values, so the same tool name can resolve to different actions
20085
20423
  * depending on what it is asked to do.
20086
20424
  */
20087
- evaluate(toolName, args) {
20425
+ evaluate(toolName, args, mode = "default") {
20088
20426
  for (const rule of this.rules) {
20089
20427
  const nameMatches = typeof rule.tool === "string" ? rule.tool === toolName : rule.tool.test(toolName);
20090
20428
  if (!nameMatches) continue;
20091
20429
  if (rule.args !== void 0 && !this.#argsMatch(rule.args, args)) continue;
20092
- return rule.action;
20430
+ return applyMode(rule.action, mode, true);
20093
20431
  }
20094
- return this.defaultAction;
20432
+ return applyMode(this.defaultAction, mode, false);
20095
20433
  }
20096
20434
  #argsMatch(matchers, args) {
20097
20435
  const call = args ?? {};
@@ -20103,27 +20441,85 @@ var PermissionEngine = class {
20103
20441
  };
20104
20442
 
20105
20443
  // src/permission-plugin.ts
20444
+ async function resolveAsk(opts, name, args, mode) {
20445
+ if (opts.canUseTool !== void 0) {
20446
+ let decision;
20447
+ try {
20448
+ decision = await opts.canUseTool(name, args, { toolName: name, mode });
20449
+ } catch {
20450
+ return { block: true, message: `permission gate error (fail-closed): ${name}` };
20451
+ }
20452
+ return decision.behavior === "deny" ? { block: true, message: decision.message ?? `denied: ${name}` } : void 0;
20453
+ }
20454
+ return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20455
+ }
20106
20456
  function createPermissionPlugin(engine, opts = {}) {
20457
+ const mode = opts.mode ?? "default";
20107
20458
  return definePlugin({
20108
20459
  name: opts.name ?? "permission-engine",
20109
20460
  version: "1.0.0",
20110
20461
  kind: "general",
20111
20462
  register(ctx) {
20112
- ctx.on("pre_tool_call", (rawCtx) => {
20463
+ ctx.on("pre_tool_call", async (rawCtx) => {
20113
20464
  const { name, args } = rawCtx;
20114
- const action = engine.evaluate(name, args);
20465
+ const action = engine.evaluate(name, args, mode);
20115
20466
  if (action === "deny") {
20116
20467
  return { block: true, message: `denied by permission engine: ${name}` };
20117
20468
  }
20118
- if (action === "ask") {
20119
- return opts.onAsk ? opts.onAsk(name) : { block: true, message: `requires approval: ${name}` };
20120
- }
20469
+ if (action === "ask") return resolveAsk(opts, name, args, mode);
20121
20470
  return void 0;
20122
20471
  });
20123
20472
  }
20124
20473
  });
20125
20474
  }
20126
20475
 
20476
+ // src/schema-normalizer.ts
20477
+ init_to_json_schema();
20478
+ function isJsonSchemaObject(s) {
20479
+ if (typeof s !== "object" || s === null) return false;
20480
+ const o = s;
20481
+ if ("$schema" in o) return true;
20482
+ return o.type === "object" && typeof o.properties === "object" && o.properties !== null;
20483
+ }
20484
+ function hasToJsonSchemaMethod(s) {
20485
+ return typeof s === "object" && s !== null && typeof s.toJsonSchema === "function";
20486
+ }
20487
+ function isZodSchema(s) {
20488
+ if (typeof s !== "object" || s === null) return false;
20489
+ const o = s;
20490
+ return typeof o.safeParse === "function" && ("_def" in o || "def" in o);
20491
+ }
20492
+ function isValibotSchema(s) {
20493
+ if (typeof s !== "object" || s === null) return false;
20494
+ const o = s;
20495
+ return o.kind === "schema" && "type" in o && typeof o.toJsonSchema !== "function";
20496
+ }
20497
+ async function normalizeSchema(schema) {
20498
+ if (isJsonSchemaObject(schema)) return schema;
20499
+ if (isValibotSchema(schema)) {
20500
+ const specifier = "@valibot/to-json-schema";
20501
+ try {
20502
+ const mod = await import(specifier);
20503
+ return mod.toJsonSchema(schema);
20504
+ } catch (err) {
20505
+ const missing = err instanceof Error && /Cannot find|Cannot resolve|ERR_MODULE_NOT_FOUND/.test(err.message);
20506
+ if (missing) {
20507
+ throw new Error(
20508
+ "normalizeSchema: a Valibot schema requires the optional '@valibot/to-json-schema' package. Install it, or use a Zod schema (the default recommendation)."
20509
+ );
20510
+ }
20511
+ throw err;
20512
+ }
20513
+ }
20514
+ if (isZodSchema(schema)) {
20515
+ return toJsonSchema(schema, { unrepresentable: "any" });
20516
+ }
20517
+ if (hasToJsonSchemaMethod(schema)) return schema.toJsonSchema();
20518
+ throw new Error(
20519
+ "normalizeSchema: unsupported schema. Supported: Zod (default), JSON Schema, ArkType (.toJsonSchema()), Valibot (with @valibot/to-json-schema)."
20520
+ );
20521
+ }
20522
+
20127
20523
  // src/security.ts
20128
20524
  init_security();
20129
20525
  var Security = class {
@@ -20176,6 +20572,96 @@ var Security = class {
20176
20572
  }
20177
20573
  };
20178
20574
 
20575
+ // src/session-manager.ts
20576
+ var SUMMARY_PREVIEW_MAX = 80;
20577
+ function createSessionManager(storage2) {
20578
+ return {
20579
+ async listSessions(opts) {
20580
+ if (typeof storage2.listConversationIds !== "function") {
20581
+ return {
20582
+ supported: false,
20583
+ reason: "storage adapter does not support listing conversations (listConversationIds)"
20584
+ };
20585
+ }
20586
+ const ids = await storage2.listConversationIds();
20587
+ if (ids === void 0) {
20588
+ return {
20589
+ supported: false,
20590
+ reason: "storage adapter reported listing as unsupported (listConversationIds \u2192 undefined)"
20591
+ };
20592
+ }
20593
+ const windowed = windowIds(ids, opts);
20594
+ const summaries = [];
20595
+ for (const id of windowed) {
20596
+ summaries.push(await buildSummary(storage2, id));
20597
+ }
20598
+ return { supported: true, value: summaries };
20599
+ },
20600
+ getSessionMessages(id, opts) {
20601
+ return storage2.getMessages(id, opts);
20602
+ },
20603
+ async renameSession(id, title) {
20604
+ if (typeof storage2.setSessionMeta !== "function") {
20605
+ return unsupportedWrite();
20606
+ }
20607
+ await storage2.setSessionMeta(id, { title });
20608
+ return { supported: true, value: void 0 };
20609
+ },
20610
+ async tagSession(id, tag) {
20611
+ if (typeof storage2.setSessionMeta !== "function") {
20612
+ return unsupportedWrite();
20613
+ }
20614
+ await storage2.setSessionMeta(id, { tag });
20615
+ return { supported: true, value: void 0 };
20616
+ }
20617
+ };
20618
+ }
20619
+ function unsupportedWrite() {
20620
+ return {
20621
+ supported: false,
20622
+ reason: "storage adapter does not support writing session metadata (setSessionMeta)"
20623
+ };
20624
+ }
20625
+ function windowIds(ids, opts) {
20626
+ const start = opts?.offset !== void 0 && opts.offset > 0 ? opts.offset : 0;
20627
+ const rawLimit = opts?.limit;
20628
+ if (rawLimit !== void 0 && rawLimit <= 0) return [];
20629
+ const end = rawLimit !== void 0 ? start + rawLimit : void 0;
20630
+ return ids.slice(start, end);
20631
+ }
20632
+ async function buildSummary(storage2, id) {
20633
+ const messages = await storage2.getMessages(id);
20634
+ const firstUser = messages.find((m) => m.role === "user")?.content;
20635
+ const firstPrompt = firstUser !== void 0 && firstUser.length > 0 ? firstUser : void 0;
20636
+ const lastModified = deriveLastModified(messages);
20637
+ const meta = typeof storage2.getSessionMeta === "function" ? await storage2.getSessionMeta(id) : void 0;
20638
+ const title = meta?.title;
20639
+ const tag = meta?.tag;
20640
+ const summary = title ?? previewOf(firstPrompt);
20641
+ return {
20642
+ id,
20643
+ messageCount: messages.length,
20644
+ ...firstPrompt !== void 0 ? { firstPrompt } : {},
20645
+ ...lastModified !== void 0 ? { lastModified } : {},
20646
+ ...title !== void 0 ? { title } : {},
20647
+ ...tag !== void 0 ? { tag } : {},
20648
+ ...summary !== void 0 ? { summary } : {}
20649
+ };
20650
+ }
20651
+ function deriveLastModified(messages) {
20652
+ let last;
20653
+ for (const m of messages) {
20654
+ if (m.at !== void 0 && (last === void 0 || m.at > last)) last = m.at;
20655
+ }
20656
+ return last;
20657
+ }
20658
+ function previewOf(text) {
20659
+ if (text === void 0) return void 0;
20660
+ const oneLine = text.replace(/\s+/g, " ").trim();
20661
+ if (oneLine.length === 0) return void 0;
20662
+ return oneLine.length > SUMMARY_PREVIEW_MAX ? `${oneLine.slice(0, SUMMARY_PREVIEW_MAX - 1)}\u2026` : oneLine;
20663
+ }
20664
+
20179
20665
  // src/session-scope.ts
20180
20666
  function scopedConversationId(scope, id) {
20181
20667
  return `${scope}__${id}`;
@@ -20196,7 +20682,7 @@ var PersistenceSchema = z.object({
20196
20682
  // src/workflow.ts
20197
20683
  init_path_guard();
20198
20684
  init_workflow();
20199
- z.object({
20685
+ var RetryPolicySchema = z.object({
20200
20686
  // EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
20201
20687
  maxAttempts: z.number().int("retry.maxAttempts must be integer").min(1, "retry.maxAttempts must be >= 1").max(20, "retry.maxAttempts must be <= 20"),
20202
20688
  initialBackoffMs: z.number().int().min(0).optional(),
@@ -20394,12 +20880,15 @@ var Workflow = class {
20394
20880
  };
20395
20881
  function agentStep(id, agent, promptTemplate, opts) {
20396
20882
  validateStepId(id);
20883
+ if (opts?.retry !== void 0) RetryPolicySchema.parse(opts.retry);
20397
20884
  return {
20398
20885
  kind: "agent",
20399
20886
  id,
20400
20887
  agent,
20401
20888
  promptTemplate,
20402
- ...{}
20889
+ ...opts?.retry !== void 0 ? { retry: opts.retry } : {},
20890
+ // SE3 — carry the turn's provenance down to `agent.send()` (metadata-only).
20891
+ ...opts?.origin !== void 0 ? { origin: opts.origin } : {}
20403
20892
  };
20404
20893
  }
20405
20894
  function validateStepId(id) {
@@ -20447,7 +20936,8 @@ function createSquad(options) {
20447
20936
  for (let i = 0; i < agents2.length; i++) {
20448
20937
  const agent = agents2[i];
20449
20938
  if (agent === void 0) continue;
20450
- builder = builder.then(agentStep(`agent-${i}`, agent, (prev) => String(prev)));
20939
+ const opts = i > 0 ? { origin: { kind: "peer", from: `agent-${i - 1}` } } : void 0;
20940
+ builder = builder.then(agentStep(`agent-${i}`, agent, (prev) => String(prev), opts));
20451
20941
  }
20452
20942
  const run = await builder.commit().run(input);
20453
20943
  return { result: run.output, status: run.status, steps: run.stepResults };
@@ -20901,6 +21391,6 @@ function safeStringify2(v) {
20901
21391
  }
20902
21392
  }
20903
21393
 
20904
- export { Agent, AgentBuilder, AgentDisposedError, AgentRunError, AuthenticationError, Budget, BudgetExceededError, ConfigurationError, Cron, EventBus, FileSystemConversationStorage, GenerateObjectError, InMemoryConversationStorage, IntegrationNotConnectedError, InvalidTaskIdError, JobQueue, Memory, MemoryAdapterError, NetworkError, PermissionEngine, RateLimitError, Security, StreamObjectError, Task, TaskNotFoundError, Theokit, TheokitAgentError, UnknownAgentError, UnsupportedBudgetOperationError, UnsupportedRunOperationError, UnsupportedTaskOperationError, UsageAccumulator, buildReplayHistory, chargeAndCheckThresholds, computeCost, createAgentFactory, createCounterBudgetTracker, createNoopMemoryProvider, createPermissionPlugin, createSquad, definePlugin, defineProvider, defineTool, extractRawId, getPricingEntry, inferApiMode, isTransientError, migrateSqliteToLance2 as migrateSqliteToLance, mkMemoryId, normalizeUsage, preflightCheck, scopedConversationId, sessionScopePrefix, toShareGptTrajectory, withCwdMutex };
21394
+ export { Agent, AgentBuilder, AgentDisposedError, AgentRunError, AuthenticationError, Budget, BudgetExceededError, ConfigurationError, Cron, EventBus, FileSystemConversationStorage, GenerateObjectError, InMemoryConversationStorage, IntegrationNotConnectedError, InvalidTaskIdError, JobQueue, Memory, MemoryAdapterError, NetworkError, PermissionEngine, RateLimitError, Security, StreamObjectError, Task, TaskNotFoundError, Theokit, TheokitAgentError, ToolError, UnknownAgentError, UnsupportedBudgetOperationError, UnsupportedRunOperationError, UnsupportedTaskOperationError, UsageAccumulator, applyMode, buildReplayHistory, chargeAndCheckThresholds, computeCost, createAgentFactory, createCounterBudgetTracker, createNoopMemoryProvider, createPermissionPlugin, createSessionManager, createSkill, createSquad, definePlugin, defineProvider, defineTool, emitRunEvent, extractRawId, getPricingEntry, inferApiMode, isTransientError, migrateSqliteToLance2 as migrateSqliteToLance, mkMemoryId, normalizeSchema, normalizeUsage, preflightCheck, scopedConversationId, sessionScopePrefix, toShareGptTrajectory, withCwdMutex };
20905
21395
  //# sourceMappingURL=index.js.map
20906
21396
  //# sourceMappingURL=index.js.map