@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
@@ -2,11 +2,11 @@
2
2
 
3
3
  var fs = require('fs');
4
4
  var crypto = require('crypto');
5
+ var zod = require('zod');
6
+ var module$1 = require('module');
5
7
  var path = require('path');
6
8
  var promises = require('fs/promises');
7
9
  var os = require('os');
8
- var zod = require('zod');
9
- var module$1 = require('module');
10
10
  var child_process = require('child_process');
11
11
  var async_hooks = require('async_hooks');
12
12
  var url = require('url');
@@ -32,6 +32,7 @@ var init_agent_builder = __esm({
32
32
  constructor(deps) {
33
33
  this.deps = deps;
34
34
  }
35
+ /** SE8 — accepts a bare-string id shorthand (`"openai/gpt-4o-mini"`) or a {@link ModelSelection}. */
35
36
  model(m) {
36
37
  this.opts.model = m;
37
38
  return this;
@@ -898,6 +899,329 @@ var init_ids = __esm({
898
899
  }
899
900
  });
900
901
 
902
+ // src/internal/runtime/config/default-model.ts
903
+ var DEFAULT_AGENTIC_MODEL_ID;
904
+ var init_default_model = __esm({
905
+ "src/internal/runtime/config/default-model.ts"() {
906
+ DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
907
+ }
908
+ });
909
+ function toJsonSchema(schema, options = { unrepresentable: "any" }) {
910
+ return zod.toJSONSchema(schema, options);
911
+ }
912
+ var init_to_json_schema = __esm({
913
+ "src/internal/zod/to-json-schema.ts"() {
914
+ }
915
+ });
916
+ function requireZod() {
917
+ if (cachedZ !== void 0) return cachedZ;
918
+ 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)));
919
+ let mod;
920
+ try {
921
+ mod = r("zod");
922
+ } catch (cause) {
923
+ throw new ConfigurationError(
924
+ 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
925
+ { code: "zod_not_installed", cause }
926
+ );
927
+ }
928
+ cachedZ = mod.z ?? mod;
929
+ return cachedZ;
930
+ }
931
+ function makeOutputTool(jsonSchema, onCapture) {
932
+ return {
933
+ name: "output",
934
+ description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
935
+ inputSchema: jsonSchema,
936
+ handler: (input) => {
937
+ const out = onCapture(input);
938
+ if (typeof out === "string") return out;
939
+ if (out instanceof Promise) return out;
940
+ return "";
941
+ }
942
+ };
943
+ }
944
+ function buildTransientAgentOptions(params) {
945
+ return {
946
+ model: params.model,
947
+ local: params.local,
948
+ tools: [params.outputTool],
949
+ systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
950
+ ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
951
+ ...params.providers !== void 0 ? { providers: params.providers } : {}
952
+ };
953
+ }
954
+ function extractUsage(result) {
955
+ const u = result.usage;
956
+ if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
957
+ return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
958
+ }
959
+ function buildToolPrompt(prompt) {
960
+ return `${prompt}
961
+
962
+ Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
963
+ }
964
+ function setupStructuredOutput(schema, maxRetries) {
965
+ const z7 = requireZod();
966
+ const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
967
+ return {
968
+ z: z7,
969
+ jsonSchema,
970
+ maxRetries: maxRetries ?? 1,
971
+ initialUsage: { inputTokens: 0, outputTokens: 0 }
972
+ };
973
+ }
974
+ async function disposeAndDeleteTransient(agent, deletor) {
975
+ await agent.dispose();
976
+ try {
977
+ await deletor(agent.agentId);
978
+ } catch {
979
+ }
980
+ }
981
+ var cachedZ;
982
+ var init_structured_output_helpers = __esm({
983
+ "src/internal/structured-output-helpers.ts"() {
984
+ init_errors();
985
+ init_to_json_schema();
986
+ }
987
+ });
988
+
989
+ // src/generate-object.ts
990
+ var generate_object_exports = {};
991
+ __export(generate_object_exports, {
992
+ GenerateObjectError: () => GenerateObjectError,
993
+ generateObjectImpl: () => generateObjectImpl
994
+ });
995
+ function salvagePartial(schema, raw) {
996
+ if (typeof raw !== "object" || raw === null) return raw;
997
+ const shape = schema.shape;
998
+ if (shape === void 0 || typeof shape !== "object") return raw;
999
+ const rawObj = raw;
1000
+ const out = {};
1001
+ for (const [key, fieldSchema] of Object.entries(shape)) {
1002
+ if (typeof fieldSchema?.safeParse !== "function") continue;
1003
+ const parsed = fieldSchema.safeParse(rawObj[key]);
1004
+ if (parsed.success) out[key] = parsed.data;
1005
+ }
1006
+ return out;
1007
+ }
1008
+ async function runReasoningPhase(options, deps) {
1009
+ const reasoningOptions = {
1010
+ model: options.model,
1011
+ local: options.local,
1012
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
1013
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
1014
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
1015
+ };
1016
+ const reasoningAgent = await deps.create(reasoningOptions);
1017
+ try {
1018
+ const run = await reasoningAgent.send(options.prompt);
1019
+ const result = await run.wait();
1020
+ const text = result.result;
1021
+ return typeof text === "string" ? text : options.prompt;
1022
+ } finally {
1023
+ await disposeAndDeleteTransient(reasoningAgent, deps.delete);
1024
+ }
1025
+ }
1026
+ async function generateObjectImpl(options, deps) {
1027
+ const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
1028
+ options.schema,
1029
+ options.maxRetries
1030
+ );
1031
+ let capturedRaw;
1032
+ let lastUsage = initialUsage;
1033
+ const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
1034
+ class CaptureSentinel extends Error {
1035
+ constructor(captured) {
1036
+ super("generate-object-capture");
1037
+ this.captured = captured;
1038
+ }
1039
+ captured;
1040
+ [sentinel] = true;
1041
+ }
1042
+ const outputTool = makeOutputTool(jsonSchema, (input) => {
1043
+ if (capturedRaw === void 0) {
1044
+ capturedRaw = input;
1045
+ }
1046
+ throw new CaptureSentinel(input);
1047
+ });
1048
+ const reasoningText = options.structuringModel !== void 0 ? await runReasoningPhase(options, deps) : void 0;
1049
+ const structuringModel = options.structuringModel ?? options.model;
1050
+ const structuringPrompt = reasoningText ?? options.prompt;
1051
+ const agentOptions = buildTransientAgentOptions({
1052
+ model: structuringModel,
1053
+ local: options.local,
1054
+ outputTool,
1055
+ ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
1056
+ ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
1057
+ ...options.providers !== void 0 ? { providers: options.providers } : {}
1058
+ });
1059
+ const agent = await deps.create(agentOptions);
1060
+ try {
1061
+ const userMessage = buildToolPrompt(structuringPrompt);
1062
+ let lastParseError;
1063
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
1064
+ capturedRaw = void 0;
1065
+ const run = await agent.send(userMessage);
1066
+ const result = await run.wait();
1067
+ lastUsage = extractUsage(result);
1068
+ if (capturedRaw === void 0) {
1069
+ if (result.status === "error" && result.error !== void 0) {
1070
+ throw new GenerateObjectError(
1071
+ "no_tool_call",
1072
+ `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
1073
+ result.error
1074
+ );
1075
+ }
1076
+ if (attempt === maxRetries) {
1077
+ throw new GenerateObjectError(
1078
+ "no_tool_call",
1079
+ "The model returned text instead of calling the `output` tool."
1080
+ );
1081
+ }
1082
+ continue;
1083
+ }
1084
+ const parsed = options.schema.safeParse(capturedRaw);
1085
+ if (parsed.success) {
1086
+ return {
1087
+ object: parsed.data,
1088
+ raw: capturedRaw,
1089
+ usage: lastUsage,
1090
+ finishReason: "tool_use"
1091
+ };
1092
+ }
1093
+ lastParseError = parsed.error;
1094
+ }
1095
+ if (options.errorStrategy === "return-raw") {
1096
+ return {
1097
+ object: capturedRaw,
1098
+ raw: capturedRaw,
1099
+ usage: lastUsage,
1100
+ finishReason: "tool_use"
1101
+ };
1102
+ }
1103
+ if (options.errorStrategy === "return-partial") {
1104
+ return {
1105
+ object: salvagePartial(options.schema, capturedRaw),
1106
+ raw: capturedRaw,
1107
+ usage: lastUsage,
1108
+ finishReason: "tool_use"
1109
+ };
1110
+ }
1111
+ throw new GenerateObjectError(
1112
+ "parse_failed",
1113
+ "Schema parse failed after all retries.",
1114
+ lastParseError
1115
+ );
1116
+ } finally {
1117
+ await disposeAndDeleteTransient(agent, deps.delete);
1118
+ }
1119
+ }
1120
+ var GenerateObjectError;
1121
+ var init_generate_object = __esm({
1122
+ "src/generate-object.ts"() {
1123
+ init_structured_output_helpers();
1124
+ GenerateObjectError = class extends Error {
1125
+ name = "GenerateObjectError";
1126
+ code;
1127
+ cause;
1128
+ constructor(code, message, cause) {
1129
+ super(message);
1130
+ this.code = code;
1131
+ if (cause !== void 0) this.cause = cause;
1132
+ }
1133
+ };
1134
+ }
1135
+ });
1136
+
1137
+ // src/internal/runtime/registry/agent-factory-registry.ts
1138
+ var agent_factory_registry_exports = {};
1139
+ __export(agent_factory_registry_exports, {
1140
+ getAgentFacade: () => getAgentFacade,
1141
+ setAgentFacade: () => setAgentFacade
1142
+ });
1143
+ function setAgentFacade(facade) {
1144
+ registered = facade;
1145
+ }
1146
+ function getAgentFacade() {
1147
+ if (registered === void 0) {
1148
+ throw new Error(
1149
+ "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
1150
+ );
1151
+ }
1152
+ return registered;
1153
+ }
1154
+ var registered;
1155
+ var init_agent_factory_registry = __esm({
1156
+ "src/internal/runtime/registry/agent-factory-registry.ts"() {
1157
+ }
1158
+ });
1159
+
1160
+ // src/agent-generate.ts
1161
+ async function agentGenerate(agent, agentModel, agentApiKey, agentLocal, input, options) {
1162
+ const { output, maxRetries, errorStrategy, ...sendOptions } = options;
1163
+ const run = await agent.send(input, sendOptions);
1164
+ const result = await run.wait();
1165
+ const { generateObjectImpl: generateObjectImpl2, GenerateObjectError: GenerateObjectError2 } = await Promise.resolve().then(() => (init_generate_object(), generate_object_exports));
1166
+ const answer = structurableAnswerOrThrow(result, GenerateObjectError2);
1167
+ const { getAgentFacade: getAgentFacade2 } = await Promise.resolve().then(() => (init_agent_factory_registry(), agent_factory_registry_exports));
1168
+ const facade = getAgentFacade2();
1169
+ const structured = await generateObjectImpl2(
1170
+ {
1171
+ prompt: answer,
1172
+ schema: output,
1173
+ // `agentModel` arrives already normalized (`this.model` passed through
1174
+ // `normalizeModel` in the LocalAgent/CloudAgent constructor), so the widened
1175
+ // `string | ModelSelection` field only ever receives a `ModelSelection` here.
1176
+ model: agentModel ?? { id: DEFAULT_AGENTIC_MODEL_ID },
1177
+ // `local` is required to keep the transient structuring agent local-only;
1178
+ // default to the process cwd when the agent had no explicit local config.
1179
+ local: agentLocal ?? { cwd: process.cwd() },
1180
+ ...agentApiKey !== void 0 ? { apiKey: agentApiKey } : {},
1181
+ ...maxRetries !== void 0 ? { maxRetries } : {},
1182
+ ...errorStrategy !== void 0 ? { errorStrategy } : {}
1183
+ },
1184
+ {
1185
+ create: (opts) => facade.create(opts),
1186
+ delete: (agentId) => facade.delete(agentId)
1187
+ }
1188
+ );
1189
+ return {
1190
+ object: structured.object,
1191
+ result,
1192
+ raw: structured.raw,
1193
+ usage: structured.usage
1194
+ };
1195
+ }
1196
+ function structurableAnswerOrThrow(result, GenerateObjectError2) {
1197
+ if (result.status === "error") {
1198
+ throw new GenerateObjectError2(
1199
+ "no_tool_call",
1200
+ `Agent run failed before an answer could be structured: ${result.error?.message ?? "unknown error"} [${result.error?.code ?? "?"}]`,
1201
+ result.error
1202
+ );
1203
+ }
1204
+ if (result.status === "cancelled") {
1205
+ throw new GenerateObjectError2(
1206
+ "no_tool_call",
1207
+ "Agent run was cancelled before an answer could be structured."
1208
+ );
1209
+ }
1210
+ const answer = result.result;
1211
+ if (answer === void 0 || answer.length === 0) {
1212
+ throw new GenerateObjectError2(
1213
+ "no_tool_call",
1214
+ "The tool loop finished with no text answer (tool-only completion) \u2014 there is nothing to structure."
1215
+ );
1216
+ }
1217
+ return answer;
1218
+ }
1219
+ var init_agent_generate = __esm({
1220
+ "src/agent-generate.ts"() {
1221
+ init_default_model();
1222
+ }
1223
+ });
1224
+
901
1225
  // src/internal/persistence/cwd-mutex.ts
902
1226
  function withCwdMutex(key, fn) {
903
1227
  const prev = tails.get(key) ?? Promise.resolve();
@@ -1067,11 +1391,21 @@ var init_path_guard = __esm({
1067
1391
  }
1068
1392
  });
1069
1393
 
1070
- // src/internal/runtime/config/default-model.ts
1071
- var DEFAULT_AGENTIC_MODEL_ID;
1072
- var init_default_model = __esm({
1073
- "src/internal/runtime/config/default-model.ts"() {
1074
- DEFAULT_AGENTIC_MODEL_ID = "google/gemini-2.0-flash-001";
1394
+ // src/internal/runtime/model-selection.ts
1395
+ function normalizeModel(m) {
1396
+ if (m === void 0 || typeof m !== "string") return m;
1397
+ const id = m.trim();
1398
+ if (id.length === 0) {
1399
+ throw new ConfigurationError(
1400
+ 'model must be a non-empty "provider/model" id string or a ModelSelection object',
1401
+ { code: "invalid_model_selection" }
1402
+ );
1403
+ }
1404
+ return { id };
1405
+ }
1406
+ var init_model_selection = __esm({
1407
+ "src/internal/runtime/model-selection.ts"() {
1408
+ init_errors();
1075
1409
  }
1076
1410
  });
1077
1411
  function detectNetworkFsName(typeMagic) {
@@ -1211,7 +1545,10 @@ var init_enabled_names = __esm({
1211
1545
  function stripSecretsFromOptions(options) {
1212
1546
  return assignDefined({
1213
1547
  name: options.name,
1214
- model: options.model !== void 0 ? { id: options.model.id } : void 0,
1548
+ model: (() => {
1549
+ const m = normalizeModel(options.model);
1550
+ return m !== void 0 ? { id: m.id } : void 0;
1551
+ })(),
1215
1552
  systemPrompt: typeof options.systemPrompt === "string" ? options.systemPrompt : void 0,
1216
1553
  local: serializeLocal(options.local),
1217
1554
  cloud: serializeCloud(options.cloud),
@@ -1382,6 +1719,7 @@ var init_agent_registry_store = __esm({
1382
1719
  init_cwd_mutex();
1383
1720
  init_schema_version();
1384
1721
  init_enabled_names();
1722
+ init_model_selection();
1385
1723
  SCHEMA_VERSION = 1;
1386
1724
  LEGACY_SCHEMA_VERSION_STRING = "1.0";
1387
1725
  REGISTRY_RELATIVE_PATH = path.join(".theokit", "agents", "registry.json");
@@ -1517,7 +1855,8 @@ function serializeCloudAgentConfig(options) {
1517
1855
  cloud: serializeCloud2(options.cloud)
1518
1856
  };
1519
1857
  if (typeof options.agentId === "string") payload.agentId = options.agentId;
1520
- if (options.model !== void 0) payload.model = { id: options.model.id };
1858
+ const cfgModel = normalizeModel(options.model);
1859
+ if (cfgModel !== void 0) payload.model = { id: cfgModel.id };
1521
1860
  if (typeof options.systemPrompt === "string") payload.systemPrompt = options.systemPrompt;
1522
1861
  const skills = serializeSkills(options.skills);
1523
1862
  if (skills !== void 0) payload.skills = skills;
@@ -1627,6 +1966,7 @@ function serializeMemory2(memory) {
1627
1966
  var init_cloud_config_serializer = __esm({
1628
1967
  "src/internal/runtime/cloud/cloud-config-serializer.ts"() {
1629
1968
  init_enabled_names();
1969
+ init_model_selection();
1630
1970
  }
1631
1971
  });
1632
1972
 
@@ -2337,6 +2677,7 @@ function applyScriptMetrics(base, script) {
2337
2677
  if (script.cost !== void 0) base.cost = script.cost;
2338
2678
  if (script.stoppedAtIterationLimit === true) base.stoppedAtIterationLimit = true;
2339
2679
  if (script.stoppedByDoomLoop === true) base.stoppedByDoomLoop = true;
2680
+ if (script.origin !== void 0) base.origin = script.origin;
2340
2681
  }
2341
2682
  var FixtureRunBase;
2342
2683
  var init_fixture_run_base = __esm({
@@ -2844,6 +3185,7 @@ function buildFixtureArtifacts() {
2844
3185
  var CloudAgent;
2845
3186
  var init_cloud_agent = __esm({
2846
3187
  "src/internal/runtime/cloud/cloud-agent.ts"() {
3188
+ init_agent_generate();
2847
3189
  init_errors();
2848
3190
  init_env();
2849
3191
  init_fixture_mode();
@@ -2851,6 +3193,7 @@ var init_cloud_agent = __esm({
2851
3193
  init_cwd_mutex();
2852
3194
  init_path_guard();
2853
3195
  init_default_model();
3196
+ init_model_selection();
2854
3197
  init_agent_registry();
2855
3198
  init_system_prompt();
2856
3199
  init_cloud_config_serializer();
@@ -2870,7 +3213,7 @@ var init_cloud_agent = __esm({
2870
3213
  disposed = false;
2871
3214
  constructor(options, providedAgentId) {
2872
3215
  this.agentId = providedAgentId ?? options.agentId ?? generateCloudAgentId();
2873
- this.model = options.model;
3216
+ this.model = normalizeModel(options.model);
2874
3217
  this.options = options;
2875
3218
  this.cloudPayload = serializeCloudAgentConfig({ ...options, agentId: this.agentId });
2876
3219
  const repoUrls = (options.cloud?.repos ?? []).map((repo) => repo.url);
@@ -2900,6 +3243,17 @@ var init_cloud_agent = __esm({
2900
3243
  const apiKey = resolveApiKey(this.options.apiKey);
2901
3244
  return isFixtureApiKey(apiKey) && getConfiguredBaseUrl() === void 0;
2902
3245
  }
3246
+ // SE9 — integrated structured output; delegates to the shared helper.
3247
+ generate(message, options) {
3248
+ return agentGenerate(
3249
+ this,
3250
+ this.model,
3251
+ this.options.apiKey,
3252
+ this.options.local,
3253
+ message,
3254
+ options
3255
+ );
3256
+ }
2903
3257
  async send(message, options = {}) {
2904
3258
  if (options.tools !== void 0 && options.tools.length > 0) {
2905
3259
  throw new ConfigurationError(
@@ -2930,7 +3284,7 @@ var init_cloud_agent = __esm({
2930
3284
  });
2931
3285
  }
2932
3286
  async sendLocked(message, options) {
2933
- const overrideModel = options.model;
3287
+ const overrideModel = normalizeModel(options.model);
2934
3288
  if (overrideModel !== void 0) {
2935
3289
  this.model = overrideModel;
2936
3290
  updateRegisteredAgent(this.agentId, { model: overrideModel });
@@ -4124,12 +4478,12 @@ function tryAutoRegisterAdapters(settings) {
4124
4478
  if (settings.autoDetect === false) return;
4125
4479
  const disabled = new Set(settings.disable ?? []);
4126
4480
  for (const adapter of ALL_ADAPTERS) {
4127
- if (registered.has(adapter.moduleName)) continue;
4481
+ if (registered2.has(adapter.moduleName)) continue;
4128
4482
  if (disabled.has(adapter.displayName.toLowerCase())) continue;
4129
4483
  if (!adapter.detect()) continue;
4130
4484
  try {
4131
4485
  adapter.register();
4132
- registered.add(adapter.moduleName);
4486
+ registered2.add(adapter.moduleName);
4133
4487
  process.stderr.write(`[theokit-sdk] telemetry: ${adapter.displayName} auto-instrumented.
4134
4488
  `);
4135
4489
  } catch (cause) {
@@ -4141,7 +4495,7 @@ function tryAutoRegisterAdapters(settings) {
4141
4495
  }
4142
4496
  }
4143
4497
  }
4144
- var ALL_ADAPTERS, registered;
4498
+ var ALL_ADAPTERS, registered2;
4145
4499
  var init_adapter_registry = __esm({
4146
4500
  "src/internal/telemetry/adapter-registry.ts"() {
4147
4501
  init_arize();
@@ -4160,7 +4514,7 @@ var init_adapter_registry = __esm({
4160
4514
  arizeAdapter,
4161
4515
  braintrustAdapter
4162
4516
  ];
4163
- registered = /* @__PURE__ */ new Set();
4517
+ registered2 = /* @__PURE__ */ new Set();
4164
4518
  }
4165
4519
  });
4166
4520
  function loadOtel() {
@@ -4751,6 +5105,30 @@ var init_pagination = __esm({
4751
5105
  "src/internal/persistence/pagination.ts"() {
4752
5106
  }
4753
5107
  });
5108
+
5109
+ // src/internal/persistence/session-meta.ts
5110
+ function applyMetaPatch(current, patch) {
5111
+ const next = {};
5112
+ if (current.title !== void 0) next.title = current.title;
5113
+ if (current.tag !== void 0) next.tag = current.tag;
5114
+ if (patch.title === null) delete next.title;
5115
+ else if (patch.title !== void 0) next.title = patch.title;
5116
+ if (patch.tag === null) delete next.tag;
5117
+ else if (patch.tag !== void 0) next.tag = patch.tag;
5118
+ return next;
5119
+ }
5120
+ function coerceSessionMeta(raw) {
5121
+ if (typeof raw !== "object" || raw === null) return void 0;
5122
+ const obj = raw;
5123
+ const meta = {};
5124
+ if (typeof obj.title === "string") meta.title = obj.title;
5125
+ if (typeof obj.tag === "string") meta.tag = obj.tag;
5126
+ return meta.title === void 0 && meta.tag === void 0 ? void 0 : meta;
5127
+ }
5128
+ var init_session_meta = __esm({
5129
+ "src/internal/persistence/session-meta.ts"() {
5130
+ }
5131
+ });
4754
5132
  function toStoredMessage(record) {
4755
5133
  return {
4756
5134
  role: record.role,
@@ -4766,7 +5144,9 @@ var init_conversation_storage_fs = __esm({
4766
5144
  "src/internal/persistence/conversation-storage-fs.ts"() {
4767
5145
  init_agent_session_store();
4768
5146
  init_security();
5147
+ init_file_lock();
4769
5148
  init_pagination();
5149
+ init_session_meta();
4770
5150
  FileSystemConversationStorage = class {
4771
5151
  #root;
4772
5152
  constructor(opts = {}) {
@@ -4816,6 +5196,37 @@ var init_conversation_storage_fs = __esm({
4816
5196
  async compact(conversationId, maxTurns) {
4817
5197
  await compactSessionFile(this.#root, conversationId, maxTurns);
4818
5198
  }
5199
+ // SE4 — session metadata persisted as a per-conversation sidecar
5200
+ // `<root>/.theokit/agents/<safeId>/session.json` (same sanitized perimeter as
5201
+ // the transcript). Kept separate from messages.jsonl so a title/tag write does
5202
+ // not rewrite the append-only log.
5203
+ #metaPath(conversationId) {
5204
+ const safe2 = sanitizeIdentifier(conversationId, { maxLen: 128 });
5205
+ return safePathJoin(this.#root, ".theokit", "agents", safe2, "session.json");
5206
+ }
5207
+ async getSessionMeta(conversationId) {
5208
+ try {
5209
+ const raw = await promises.readFile(this.#metaPath(conversationId), "utf8");
5210
+ return coerceSessionMeta(JSON.parse(raw));
5211
+ } catch (cause) {
5212
+ if (cause.code === "ENOENT") return void 0;
5213
+ throw cause;
5214
+ }
5215
+ }
5216
+ async setSessionMeta(conversationId, patch) {
5217
+ const metaPath = this.#metaPath(conversationId);
5218
+ await promises.mkdir(path.dirname(metaPath), { recursive: true });
5219
+ await withFileLock(metaPath, async () => {
5220
+ let current = {};
5221
+ try {
5222
+ current = coerceSessionMeta(JSON.parse(await promises.readFile(metaPath, "utf8"))) ?? {};
5223
+ } catch (cause) {
5224
+ if (cause.code !== "ENOENT") throw cause;
5225
+ }
5226
+ const next = applyMetaPatch(current, patch);
5227
+ await promises.writeFile(metaPath, redactSecrets(JSON.stringify(next)), "utf8");
5228
+ });
5229
+ }
4819
5230
  async dispose() {
4820
5231
  }
4821
5232
  };
@@ -6807,23 +7218,27 @@ var init_skills_manager = __esm({
6807
7218
  "src/internal/runtime/skills/skills-manager.ts"() {
6808
7219
  init_discover_skills();
6809
7220
  SkillsManager = class {
6810
- constructor(cwd, _enabled, settingSourcesIncludeProject) {
7221
+ constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
6811
7222
  this.cwd = cwd;
6812
7223
  this.settingSourcesIncludeProject = settingSourcesIncludeProject;
7224
+ this.skillsDir = skillsDir;
7225
+ this.inline = inline;
6813
7226
  }
6814
7227
  cwd;
6815
7228
  settingSourcesIncludeProject;
7229
+ skillsDir;
7230
+ inline;
6816
7231
  skills = [];
6817
7232
  async initialize() {
6818
7233
  if (!this.settingSourcesIncludeProject) {
6819
- this.skills = [];
7234
+ this.skills = this.mergeInline([]);
6820
7235
  return;
6821
7236
  }
6822
7237
  await this.refresh();
6823
7238
  }
6824
7239
  async refresh() {
6825
- const skillsRoot = path.join(this.cwd, ".theokit", "skills");
6826
- this.skills = await discoverSkills(skillsRoot, {
7240
+ const skillsRoot = this.skillsDir ?? path.join(this.cwd, ".theokit", "skills");
7241
+ const discovered = await discoverSkills(skillsRoot, {
6827
7242
  onInvalidSkill: (info) => {
6828
7243
  process.stderr.write(
6829
7244
  `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
@@ -6831,6 +7246,13 @@ var init_skills_manager = __esm({
6831
7246
  );
6832
7247
  }
6833
7248
  });
7249
+ this.skills = this.mergeInline(discovered);
7250
+ }
7251
+ /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
7252
+ mergeInline(discovered) {
7253
+ if (this.inline === void 0 || this.inline.length === 0) return discovered;
7254
+ const inlineNames = new Set(this.inline.map((s) => s.name));
7255
+ return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
6834
7256
  }
6835
7257
  list() {
6836
7258
  return Promise.resolve(this.skills);
@@ -6868,7 +7290,7 @@ function bootstrapSubmanagers(args) {
6868
7290
  const providerCount = (args.options.providers?.routes?.length ?? 0) + enabledPluginNames(args.options.plugins).length;
6869
7291
  if (providerCount > 0 || args.options.providers !== void 0) {
6870
7292
  out.providers = new ProvidersManagerImpl(
6871
- args.options.model,
7293
+ normalizeModel(args.options.model),
6872
7294
  args.options.providers,
6873
7295
  args.options.plugins
6874
7296
  );
@@ -6877,7 +7299,10 @@ function bootstrapSubmanagers(args) {
6877
7299
  out.skillsManager = new SkillsManager(
6878
7300
  args.workspaceCwd,
6879
7301
  args.options.skills?.enabled,
6880
- args.settingSourcesIncludeProject
7302
+ args.settingSourcesIncludeProject,
7303
+ // M22 — custom skills directory + inline (code-defined) skills.
7304
+ args.options.skills?.skillsDir,
7305
+ args.options.skills?.inline
6881
7306
  );
6882
7307
  const localSkills = out.skillsManager;
6883
7308
  out.skills = { list: () => localSkills.list() };
@@ -6902,6 +7327,7 @@ var init_local_agent_bootstrap = __esm({
6902
7327
  init_enabled_names();
6903
7328
  init_providers_manager();
6904
7329
  init_context_manager();
7330
+ init_model_selection();
6905
7331
  init_plugins_manager();
6906
7332
  init_agent_registry();
6907
7333
  init_skills_manager();
@@ -6950,6 +7376,7 @@ function createLocalRun(options) {
6950
7376
  projectMcpServers: options.projectMcpServers,
6951
7377
  ...options.persistMemoryFact !== void 0 ? { persistMemoryFact: options.persistMemoryFact } : {}
6952
7378
  });
7379
+ if (options.sendOptions.origin !== void 0) script.origin = options.sendOptions.origin;
6953
7380
  const handle = new LocalRun({
6954
7381
  id,
6955
7382
  agentId: options.agentId,
@@ -7650,6 +8077,19 @@ var init_loop_llm_stream = __esm({
7650
8077
  init_message_builders();
7651
8078
  }
7652
8079
  });
8080
+
8081
+ // src/types/run-events.ts
8082
+ function emitRunEvent(sink, event) {
8083
+ if (sink === void 0) return;
8084
+ try {
8085
+ sink(event);
8086
+ } catch {
8087
+ }
8088
+ }
8089
+ var init_run_events = __esm({
8090
+ "src/types/run-events.ts"() {
8091
+ }
8092
+ });
7653
8093
  async function withToolWhitelist(whitelist, fn) {
7654
8094
  return toolWhitelistStore.run(whitelist, fn);
7655
8095
  }
@@ -7821,6 +8261,27 @@ var init_repair_middleware = __esm({
7821
8261
  }
7822
8262
  });
7823
8263
 
8264
+ // src/tool-error.ts
8265
+ function renderToolErrorMessage(content) {
8266
+ if (typeof content === "string") return content;
8267
+ return content.map((block) => block.type === "text" ? block.text : `[${block.source.media_type} image]`).join("\n");
8268
+ }
8269
+ var ToolError;
8270
+ var init_tool_error = __esm({
8271
+ "src/tool-error.ts"() {
8272
+ init_errors();
8273
+ ToolError = class extends TheokitAgentError {
8274
+ name = "ToolError";
8275
+ /** The error content surfaced to the model: a string, or text/image blocks. */
8276
+ content;
8277
+ constructor(content, options = {}) {
8278
+ super(renderToolErrorMessage(content), { ...options, isRetryable: false });
8279
+ this.content = content;
8280
+ }
8281
+ };
8282
+ }
8283
+ });
8284
+
7824
8285
  // src/internal/runtime/tools/shell-tool.ts
7825
8286
  async function runShell(options) {
7826
8287
  if (options.sandbox === true && isObviouslyUnsafe(options.command)) {
@@ -7879,9 +8340,13 @@ async function runHandlerTool(kind, handler, call, signal, context) {
7879
8340
  return { stdout: "", stderr: `${kind} tool ${call.name} has no handler`, exitCode: 127 };
7880
8341
  }
7881
8342
  try {
7882
- const stdout = await handler(call.input, { signal, context });
7883
- return { stdout, stderr: "", exitCode: 0 };
8343
+ const out = await handler(call.input, { signal, context });
8344
+ if (typeof out !== "string") return { stdout: "", stderr: "", exitCode: 0, content: out };
8345
+ return { stdout: out, stderr: "", exitCode: 0 };
7884
8346
  } catch (cause) {
8347
+ if (cause instanceof ToolError) {
8348
+ return { stdout: "", stderr: cause.message, exitCode: 1, content: cause.content };
8349
+ }
7885
8350
  const message = cause instanceof Error ? cause.message : String(cause);
7886
8351
  return { stdout: "", stderr: message, exitCode: 1 };
7887
8352
  }
@@ -7926,6 +8391,7 @@ ${result.stderr}`.trim();
7926
8391
  }
7927
8392
  var init_tool_executors = __esm({
7928
8393
  "src/internal/agent-loop/tool-executors.ts"() {
8394
+ init_tool_error();
7929
8395
  init_shell_tool();
7930
8396
  }
7931
8397
  });
@@ -8010,6 +8476,11 @@ async function dispatchSingleCall(inputs, tools, call, events, parentSpan) {
8010
8476
  toolSpan?.end();
8011
8477
  return fileVeto;
8012
8478
  }
8479
+ emitRunEvent(inputs.runEventSink, {
8480
+ type: "tool_progress",
8481
+ toolName: workingCall.name,
8482
+ toolCallId: callId
8483
+ });
8013
8484
  const result = await runToolWithLifecycle(inputs, resolved, workingCall, callId);
8014
8485
  await inputs.pluginManager?.runPostToolCallHooks({
8015
8486
  name: workingCall.name,
@@ -8036,6 +8507,13 @@ function applyRepairAndExtractCall(tools, call) {
8036
8507
  function vetoFromForkWhitelist(inputs, call, callId, events) {
8037
8508
  const whitelistDecision = checkToolWhitelist(call.name);
8038
8509
  if (whitelistDecision.allowed) return void 0;
8510
+ emitRunEvent(inputs.runEventSink, {
8511
+ type: "permission_denied",
8512
+ toolName: call.name,
8513
+ toolCallId: callId,
8514
+ source: "fork_whitelist",
8515
+ message: whitelistDecision.reason ?? "tool not available in fork"
8516
+ });
8039
8517
  events.push(buildToolUseRunning(inputs, callId, call));
8040
8518
  events.push(
8041
8519
  buildToolUseCompleted(inputs, callId, call, {
@@ -8072,6 +8550,13 @@ async function vetoFromPluginPreHook(inputs, call, callId, events) {
8072
8550
  runId: inputs.runId
8073
8551
  });
8074
8552
  if (pluginVeto === void 0) return void 0;
8553
+ emitRunEvent(inputs.runEventSink, {
8554
+ type: "permission_denied",
8555
+ toolName: call.name,
8556
+ toolCallId: callId,
8557
+ source: "plugin",
8558
+ message: pluginVeto.message
8559
+ });
8075
8560
  events.push(
8076
8561
  buildToolUseCompleted(inputs, callId, call, {
8077
8562
  stdout: "",
@@ -8094,6 +8579,13 @@ async function vetoFromFileHookPreDecision(inputs, call, callId, events) {
8094
8579
  runId: inputs.runId
8095
8580
  });
8096
8581
  if (!preDecision.blocked) return void 0;
8582
+ emitRunEvent(inputs.runEventSink, {
8583
+ type: "permission_denied",
8584
+ toolName: call.name,
8585
+ toolCallId: callId,
8586
+ source: "file_hook",
8587
+ message: preDecision.reason ?? "blocked by hook"
8588
+ });
8097
8589
  events.push(
8098
8590
  buildToolUseCompleted(inputs, callId, call, {
8099
8591
  stdout: "",
@@ -8137,7 +8629,9 @@ async function runToolWithLifecycle(inputs, resolved, call, callId) {
8137
8629
  await safeEmitToolHook(inputs.onToolEnd, {
8138
8630
  toolName: call.name,
8139
8631
  args: call.input,
8140
- result: result.stdout,
8632
+ // SE7 — a block-returning handler has empty `stdout`; surface its structured
8633
+ // content to the hook instead of an empty string.
8634
+ result: result.content !== void 0 ? result.content : result.stdout,
8141
8635
  conversationId: inputs.agentId,
8142
8636
  callId,
8143
8637
  durationMs
@@ -8159,7 +8653,10 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
8159
8653
  output: {
8160
8654
  stdout: result.stdout,
8161
8655
  stderr: result.stderr,
8162
- exitCode: result.exitCode ?? 0
8656
+ exitCode: result.exitCode ?? 0,
8657
+ // SE7 — structured content (text + image blocks) when the handler
8658
+ // returned/threw blocks; absent for the string path.
8659
+ ...result.content !== void 0 ? { content: result.content } : {}
8163
8660
  },
8164
8661
  agentId: inputs.agentId,
8165
8662
  runId: inputs.runId
@@ -8172,7 +8669,9 @@ function finalizeSpanAndPostHook(inputs, call, callId, result, events, toolSpan)
8172
8669
  return {
8173
8670
  type: "tool_result",
8174
8671
  toolUseId: call.id,
8175
- content: renderToolResult(result),
8672
+ // SE7 — structured content blocks (handler-returned or ToolError-carried)
8673
+ // are authoritative; otherwise the legacy string rendering.
8674
+ content: result.content !== void 0 ? result.content : renderToolResult(result),
8176
8675
  ...result.exitCode !== 0 && result.exitCode !== void 0 ? { isError: true } : {}
8177
8676
  };
8178
8677
  }
@@ -8222,6 +8721,7 @@ function buildToolUseCompleted(inputs, callId, call, result) {
8222
8721
  }
8223
8722
  var init_tool_dispatch = __esm({
8224
8723
  "src/internal/agent-loop/tool-dispatch.ts"() {
8724
+ init_run_events();
8225
8725
  init_ids();
8226
8726
  init_async_local_storage();
8227
8727
  init_map_with_concurrency();
@@ -8232,6 +8732,33 @@ var init_tool_dispatch = __esm({
8232
8732
  }
8233
8733
  });
8234
8734
 
8735
+ // src/internal/llm/tool-result-content.ts
8736
+ function toBlockToolResultContent(content) {
8737
+ return content;
8738
+ }
8739
+ function toStringToolResultContent(content, providerName) {
8740
+ if (typeof content === "string") return content;
8741
+ if (content.some((block) => block.type === "image")) {
8742
+ throw new ConfigurationError(
8743
+ `provider "${providerName}" does not support image content in tool results`
8744
+ );
8745
+ }
8746
+ return content.filter(
8747
+ (block) => block.type === "text"
8748
+ ).map((block) => block.text).join("\n");
8749
+ }
8750
+ function renderToolResultContentText(content, fn) {
8751
+ if (typeof content === "string") return fn(content);
8752
+ return content.map(
8753
+ (block) => block.type === "text" ? { type: "text", text: fn(block.text) } : block
8754
+ );
8755
+ }
8756
+ var init_tool_result_content = __esm({
8757
+ "src/internal/llm/tool-result-content.ts"() {
8758
+ init_errors();
8759
+ }
8760
+ });
8761
+
8235
8762
  // src/internal/agent-loop/tool-result-guard.ts
8236
8763
  function guardText(content, opts) {
8237
8764
  let out = content;
@@ -8249,12 +8776,17 @@ ${CLOSE}`;
8249
8776
  function applyToolResultGuard(parts, opts) {
8250
8777
  if (opts.delimit !== true && opts.redactPii !== true) return parts;
8251
8778
  return parts.map(
8252
- (p) => p.type === "tool_result" ? { ...p, content: guardText(p.content, opts) } : p
8779
+ (p) => (
8780
+ // SE7 — guard the TEXT of a tool result (string or the text blocks of a
8781
+ // structured content); image blocks pass through untouched.
8782
+ p.type === "tool_result" ? { ...p, content: renderToolResultContentText(p.content, (t) => guardText(t, opts)) } : p
8783
+ )
8253
8784
  );
8254
8785
  }
8255
8786
  var OPEN, CLOSE, PII_PATTERNS;
8256
8787
  var init_tool_result_guard = __esm({
8257
8788
  "src/internal/agent-loop/tool-result-guard.ts"() {
8789
+ init_tool_result_content();
8258
8790
  OPEN = "<untrusted-tool-output>";
8259
8791
  CLOSE = "</untrusted-tool-output>";
8260
8792
  PII_PATTERNS = [
@@ -9287,8 +9819,8 @@ var init_vertex = __esm({
9287
9819
 
9288
9820
  // src/internal/providers/builtin/index.ts
9289
9821
  function registerBuiltins() {
9290
- if (registered2) return;
9291
- registered2 = true;
9822
+ if (registered3) return;
9823
+ registered3 = true;
9292
9824
  registerProvider(ANTHROPIC);
9293
9825
  registerProvider(OPENAI);
9294
9826
  registerProvider(OPENROUTER);
@@ -9300,7 +9832,7 @@ function registerBuiltins() {
9300
9832
  registerProvider(VERTEX);
9301
9833
  registerCatalogProviders();
9302
9834
  }
9303
- var registered2;
9835
+ var registered3;
9304
9836
  var init_builtin = __esm({
9305
9837
  "src/internal/providers/builtin/index.ts"() {
9306
9838
  init_catalog_loader();
@@ -9314,7 +9846,7 @@ var init_builtin = __esm({
9314
9846
  init_openai();
9315
9847
  init_openrouter();
9316
9848
  init_vertex();
9317
- registered2 = false;
9849
+ registered3 = false;
9318
9850
  }
9319
9851
  });
9320
9852
 
@@ -9559,7 +10091,9 @@ function toAnthropicWireMessage(message) {
9559
10091
  return {
9560
10092
  type: "tool_result",
9561
10093
  tool_use_id: part.toolUseId,
9562
- content: part.content,
10094
+ // SE7 — this wire is block-capable: strings pass through, structured
10095
+ // text/image blocks are forwarded natively.
10096
+ content: toBlockToolResultContent(part.content),
9563
10097
  ...part.isError === true ? { is_error: true } : {}
9564
10098
  };
9565
10099
  });
@@ -9636,6 +10170,7 @@ function encodeAnthropicSystem(system) {
9636
10170
  var init_anthropic_shared = __esm({
9637
10171
  "src/internal/llm/anthropic-shared.ts"() {
9638
10172
  init_finish();
10173
+ init_tool_result_content();
9639
10174
  }
9640
10175
  });
9641
10176
 
@@ -10590,7 +11125,8 @@ function toOllamaMessages(message) {
10590
11125
  if (part.type === "tool_result") {
10591
11126
  out.push({
10592
11127
  role: "tool",
10593
- content: part.content,
11128
+ // SE7 — string-only tool role: text blocks flatten; image fails fast.
11129
+ content: toStringToolResultContent(part.content, "ollama"),
10594
11130
  tool_name: part.toolUseId
10595
11131
  });
10596
11132
  }
@@ -10631,6 +11167,7 @@ var init_ollama_native = __esm({
10631
11167
  "src/internal/llm/ollama-native.ts"() {
10632
11168
  init_ollama2();
10633
11169
  init_finish();
11170
+ init_tool_result_content();
10634
11171
  OllamaNativeClient = class {
10635
11172
  constructor(options) {
10636
11173
  this.options = options;
@@ -10995,7 +11532,9 @@ function userOrToolMessages(message) {
10995
11532
  out.push({
10996
11533
  role: "tool",
10997
11534
  tool_call_id: part.toolUseId,
10998
- content: part.content
11535
+ // SE7 — this wire's tool role is string-only: text blocks flatten; an
11536
+ // image block fails fast (ConfigurationError).
11537
+ content: toStringToolResultContent(part.content, "openai")
10999
11538
  });
11000
11539
  }
11001
11540
  }
@@ -11026,6 +11565,7 @@ var init_openai2 = __esm({
11026
11565
  init_finish();
11027
11566
  init_hermes_tool_extract();
11028
11567
  init_sse();
11568
+ init_tool_result_content();
11029
11569
  OpenAIClient = class {
11030
11570
  constructor(options) {
11031
11571
  this.options = options;
@@ -12265,18 +12805,20 @@ var init_personality_filter = __esm({
12265
12805
  function createRealLocalRun(options) {
12266
12806
  const { userText, id, startTime } = prepareRunContext(options.message);
12267
12807
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
12268
- const unusedFixtureScript = {
12808
+ const runScript = {
12269
12809
  events: [],
12270
12810
  finalStatus: "running",
12271
12811
  cancellable: false,
12272
- conversation: []
12812
+ conversation: [],
12813
+ // SE3 — carry the turn's provenance so buildResult forwards it onto RunResult.origin.
12814
+ ...options.sendOptions.origin !== void 0 ? { origin: options.sendOptions.origin } : {}
12273
12815
  };
12274
12816
  const handle = new RealLocalRun(
12275
12817
  {
12276
12818
  id,
12277
12819
  agentId: options.agentId,
12278
12820
  model: options.model,
12279
- script: unusedFixtureScript,
12821
+ script: runScript,
12280
12822
  supportedOps: supported,
12281
12823
  startTime
12282
12824
  },
@@ -12387,6 +12929,8 @@ function buildLoopInputs(options, runId, userText) {
12387
12929
  // M7 — forward SendOptions.context to the loop so every tool handler receives
12388
12930
  // it on `ctx.context` (shared run config set once, e.g. projectRoot).
12389
12931
  ...options.sendOptions.context !== void 0 ? { context: options.sendOptions.context } : {},
12932
+ // SE2 — forward the opt-in typed runtime-event sink to the loop.
12933
+ ...options.sendOptions.onRunEvent !== void 0 ? { runEventSink: options.sendOptions.onRunEvent } : {},
12390
12934
  // #58 / #57 — forward the per-tool timeout + tool-result guard so a consumer
12391
12935
  // can enable them via SendOptions (not only internal AgentLoopInputs).
12392
12936
  ...options.sendOptions.perToolTimeoutMs !== void 0 ? { perToolTimeoutMs: options.sendOptions.perToolTimeoutMs } : {},
@@ -15460,29 +16004,6 @@ var init_judge_call = __esm({
15460
16004
  }
15461
16005
  });
15462
16006
 
15463
- // src/internal/runtime/registry/agent-factory-registry.ts
15464
- var agent_factory_registry_exports = {};
15465
- __export(agent_factory_registry_exports, {
15466
- getAgentFacade: () => getAgentFacade,
15467
- setAgentFacade: () => setAgentFacade
15468
- });
15469
- function setAgentFacade(facade) {
15470
- registered3 = facade;
15471
- }
15472
- function getAgentFacade() {
15473
- if (registered3 === void 0) {
15474
- throw new Error(
15475
- "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
15476
- );
15477
- }
15478
- return registered3;
15479
- }
15480
- var registered3;
15481
- var init_agent_factory_registry = __esm({
15482
- "src/internal/runtime/registry/agent-factory-registry.ts"() {
15483
- }
15484
- });
15485
-
15486
16007
  // src/internal/runtime/lifecycle/run-to-completion.ts
15487
16008
  var run_to_completion_exports = {};
15488
16009
  __export(run_to_completion_exports, {
@@ -15647,14 +16168,14 @@ async function forkAgentImpl(parent, options, deps) {
15647
16168
  return {
15648
16169
  result: result.result,
15649
16170
  toolCalls: [],
15650
- usage: extractUsage(result)
16171
+ usage: extractUsage2(result)
15651
16172
  };
15652
16173
  });
15653
16174
  } finally {
15654
16175
  await fork.dispose();
15655
16176
  }
15656
16177
  }
15657
- function extractUsage(result) {
16178
+ function extractUsage2(result) {
15658
16179
  if (typeof result !== "object" || result === null) {
15659
16180
  return { inputTokens: 0, outputTokens: 0 };
15660
16181
  }
@@ -15813,7 +16334,7 @@ var init_local_agent_memory_hooks = __esm({
15813
16334
  async function executeSendLocked(inputs, message, options) {
15814
16335
  if (inputs.disposed) throw new AgentDisposedError(inputs.agentId);
15815
16336
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
15816
- inputs.applyModelOverride(options.model);
16337
+ inputs.applyModelOverride(normalizeModel(options.model));
15817
16338
  const userText = typeof message === "string" ? message : message.text;
15818
16339
  if (inputs.options.onBeforeSend !== void 0) {
15819
16340
  await inputs.options.onBeforeSend({
@@ -15882,6 +16403,7 @@ var init_local_agent_send = __esm({
15882
16403
  init_abort_utils();
15883
16404
  init_memory_path_selector();
15884
16405
  init_memory_store();
16406
+ init_model_selection();
15885
16407
  init_agent_session();
15886
16408
  init_safe_call();
15887
16409
  init_local_agent_invalidate();
@@ -16461,6 +16983,7 @@ function includesSetting(options, source) {
16461
16983
  var LocalAgent;
16462
16984
  var init_local_agent = __esm({
16463
16985
  "src/internal/runtime/local-agent/local-agent.ts"() {
16986
+ init_agent_generate();
16464
16987
  init_errors();
16465
16988
  init_ids();
16466
16989
  init_cwd_mutex();
@@ -16471,6 +16994,7 @@ var init_local_agent = __esm({
16471
16994
  init_hooks_executor();
16472
16995
  init_post_run_lifecycle();
16473
16996
  init_memory_path_selector();
16997
+ init_model_selection();
16474
16998
  init_agent_registry();
16475
16999
  init_live_agent_registry();
16476
17000
  init_agent_session();
@@ -16547,7 +17071,7 @@ var init_local_agent = __esm({
16547
17071
  constructor(options) {
16548
17072
  this.agentId = options.agentId ?? generateLocalAgentId();
16549
17073
  this._telemetry = createTelemetry(options.telemetry);
16550
- this.model = options.model;
17074
+ this.model = normalizeModel(options.model);
16551
17075
  this.options = options;
16552
17076
  this.workspaceCwd = resolveCwd(options.local?.cwd);
16553
17077
  this.conversationStorage = options.conversationStorage;
@@ -16614,6 +17138,11 @@ var init_local_agent = __esm({
16614
17138
  hooks() {
16615
17139
  return this.hooksExecutor;
16616
17140
  }
17141
+ // SE9 — integrated structured output; delegates to the shared helper.
17142
+ generate(message, options) {
17143
+ const { apiKey, local } = this.options;
17144
+ return agentGenerate(this, this.model, apiKey, local, message, options);
17145
+ }
16617
17146
  async send(message, options = {}) {
16618
17147
  if (options.tools !== void 0 && options.tools.length > 0) {
16619
17148
  validateToolCatalog(options.tools);
@@ -16846,6 +17375,7 @@ var init_local_agent = __esm({
16846
17375
  }
16847
17376
  });
16848
17377
  async function runCreateUnderSpan(options, span) {
17378
+ options = { ...options, model: normalizeModel(options.model) };
16849
17379
  validateAgentOptions(options);
16850
17380
  validateCloudToolParity(options);
16851
17381
  await guardAgainstIdCollision(options);
@@ -16919,7 +17449,10 @@ async function createLocalAgent(options) {
16919
17449
  const willFlowToProvider = !isFixtureApiKey(apiKey) && !shouldUseRealLocalRuntime(apiKey);
16920
17450
  const shape = validateApiKeyShape(apiKey, {
16921
17451
  strict: willFlowToProvider,
16922
- ...willFlowToProvider ? { provider: providerFromModelId(options.model?.id) } : {}
17452
+ // `options.model` is already normalized by `runCreateUnderSpan`; `normalizeModel`
17453
+ // here is the idempotent narrowing of the widened public type (`{id}` passes
17454
+ // through by reference) — cleaner than an `as` cast.
17455
+ ...willFlowToProvider ? { provider: providerFromModelId(normalizeModel(options.model)?.id) } : {}
16923
17456
  });
16924
17457
  if (shape.malformed) {
16925
17458
  throw new AuthenticationError(shape.message, { code: "malformed_api_key" });
@@ -16985,6 +17518,10 @@ async function rehydrateExistingAgent(agentId, existing, options) {
16985
17518
  ...existing.options,
16986
17519
  ...options,
16987
17520
  ...mergedLocal !== void 0 ? { local: mergedLocal } : {},
17521
+ // SE8 — normalize a caller-supplied bare-string model override at this resume
17522
+ // boundary (Agent.resume never flows through runCreateUnderSpan). Cloud resume
17523
+ // honors it; local resume forces the persisted model below.
17524
+ model: normalizeModel(options.model ?? existing.options.model),
16988
17525
  mcpServers: void 0,
16989
17526
  agentId
16990
17527
  };
@@ -17067,216 +17604,11 @@ var init_agent_helpers = __esm({
17067
17604
  init_cloud_agent();
17068
17605
  init_cloud_tool_parity();
17069
17606
  init_local_agent();
17607
+ init_model_selection();
17070
17608
  init_agent_registry();
17071
17609
  init_validate_agent_options();
17072
17610
  }
17073
17611
  });
17074
- function toJsonSchema(schema, options = { unrepresentable: "any" }) {
17075
- return zod.toJSONSchema(schema, options);
17076
- }
17077
- var init_to_json_schema = __esm({
17078
- "src/internal/zod/to-json-schema.ts"() {
17079
- }
17080
- });
17081
- function requireZod() {
17082
- if (cachedZ !== void 0) return cachedZ;
17083
- 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)));
17084
- let mod;
17085
- try {
17086
- mod = r("zod");
17087
- } catch (cause) {
17088
- throw new ConfigurationError(
17089
- 'Structured output requires the optional peer dependency `zod`. Add `"zod": "^3.25.0 || ^4.0.0"` to your package.json and reinstall.',
17090
- { code: "zod_not_installed", cause }
17091
- );
17092
- }
17093
- cachedZ = mod.z ?? mod;
17094
- return cachedZ;
17095
- }
17096
- function makeOutputTool(jsonSchema, onCapture) {
17097
- return {
17098
- name: "output",
17099
- description: "Call this tool with your final structured answer. Match the JSON schema exactly.",
17100
- inputSchema: jsonSchema,
17101
- handler: (input) => {
17102
- const out = onCapture(input);
17103
- if (typeof out === "string") return out;
17104
- if (out instanceof Promise) return out;
17105
- return "";
17106
- }
17107
- };
17108
- }
17109
- function buildTransientAgentOptions(params) {
17110
- return {
17111
- model: params.model,
17112
- local: params.local,
17113
- tools: [params.outputTool],
17114
- systemPrompt: params.systemPrompt ?? "You produce structured output by calling the `output` tool exactly once. Match the JSON schema.",
17115
- ...params.apiKey !== void 0 ? { apiKey: params.apiKey } : {},
17116
- ...params.providers !== void 0 ? { providers: params.providers } : {}
17117
- };
17118
- }
17119
- function extractUsage2(result) {
17120
- const u = result.usage;
17121
- if (u === void 0) return { inputTokens: 0, outputTokens: 0 };
17122
- return { inputTokens: u.inputTokens ?? 0, outputTokens: u.outputTokens ?? 0 };
17123
- }
17124
- function buildToolPrompt(prompt) {
17125
- return `${prompt}
17126
-
17127
- Respond by calling the \`output\` tool with the structured answer that matches the schema.`;
17128
- }
17129
- function setupStructuredOutput(schema, maxRetries) {
17130
- const z7 = requireZod();
17131
- const jsonSchema = toJsonSchema(schema, { unrepresentable: "any" });
17132
- return {
17133
- z: z7,
17134
- jsonSchema,
17135
- maxRetries: maxRetries ?? 1,
17136
- initialUsage: { inputTokens: 0, outputTokens: 0 }
17137
- };
17138
- }
17139
- async function disposeAndDeleteTransient(agent, deletor) {
17140
- await agent.dispose();
17141
- try {
17142
- await deletor(agent.agentId);
17143
- } catch {
17144
- }
17145
- }
17146
- var cachedZ;
17147
- var init_structured_output_helpers = __esm({
17148
- "src/internal/structured-output-helpers.ts"() {
17149
- init_errors();
17150
- init_to_json_schema();
17151
- }
17152
- });
17153
-
17154
- // src/generate-object.ts
17155
- var generate_object_exports = {};
17156
- __export(generate_object_exports, {
17157
- GenerateObjectError: () => GenerateObjectError,
17158
- generateObjectImpl: () => generateObjectImpl
17159
- });
17160
- function salvagePartial(schema, raw) {
17161
- if (typeof raw !== "object" || raw === null) return raw;
17162
- const shape = schema.shape;
17163
- if (shape === void 0 || typeof shape !== "object") return raw;
17164
- const rawObj = raw;
17165
- const out = {};
17166
- for (const [key, fieldSchema] of Object.entries(shape)) {
17167
- if (typeof fieldSchema?.safeParse !== "function") continue;
17168
- const parsed = fieldSchema.safeParse(rawObj[key]);
17169
- if (parsed.success) out[key] = parsed.data;
17170
- }
17171
- return out;
17172
- }
17173
- async function generateObjectImpl(options, deps) {
17174
- const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(
17175
- options.schema,
17176
- options.maxRetries
17177
- );
17178
- let capturedRaw;
17179
- let lastUsage = initialUsage;
17180
- const sentinel = /* @__PURE__ */ Symbol("generate-object-sentinel");
17181
- class CaptureSentinel extends Error {
17182
- constructor(captured) {
17183
- super("generate-object-capture");
17184
- this.captured = captured;
17185
- }
17186
- captured;
17187
- [sentinel] = true;
17188
- }
17189
- const outputTool = makeOutputTool(jsonSchema, (input) => {
17190
- if (capturedRaw === void 0) {
17191
- capturedRaw = input;
17192
- }
17193
- throw new CaptureSentinel(input);
17194
- });
17195
- const agentOptions = buildTransientAgentOptions({
17196
- model: options.model,
17197
- local: options.local,
17198
- outputTool,
17199
- ...options.systemPrompt !== void 0 ? { systemPrompt: options.systemPrompt } : {},
17200
- ...options.apiKey !== void 0 ? { apiKey: options.apiKey } : {},
17201
- ...options.providers !== void 0 ? { providers: options.providers } : {}
17202
- });
17203
- const agent = await deps.create(agentOptions);
17204
- try {
17205
- const userMessage = buildToolPrompt(options.prompt);
17206
- let lastParseError;
17207
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
17208
- capturedRaw = void 0;
17209
- const run = await agent.send(userMessage);
17210
- const result = await run.wait();
17211
- lastUsage = extractUsage2(result);
17212
- if (capturedRaw === void 0) {
17213
- if (result.status === "error" && result.error !== void 0) {
17214
- throw new GenerateObjectError(
17215
- "no_tool_call",
17216
- `Agent run failed before the model could reply: ${result.error.message ?? "unknown error"} [${result.error.code ?? "?"}]`,
17217
- result.error
17218
- );
17219
- }
17220
- if (attempt === maxRetries) {
17221
- throw new GenerateObjectError(
17222
- "no_tool_call",
17223
- "The model returned text instead of calling the `output` tool."
17224
- );
17225
- }
17226
- continue;
17227
- }
17228
- const parsed = options.schema.safeParse(capturedRaw);
17229
- if (parsed.success) {
17230
- return {
17231
- object: parsed.data,
17232
- raw: capturedRaw,
17233
- usage: lastUsage,
17234
- finishReason: "tool_use"
17235
- };
17236
- }
17237
- lastParseError = parsed.error;
17238
- }
17239
- if (options.errorStrategy === "return-raw") {
17240
- return {
17241
- object: capturedRaw,
17242
- raw: capturedRaw,
17243
- usage: lastUsage,
17244
- finishReason: "tool_use"
17245
- };
17246
- }
17247
- if (options.errorStrategy === "return-partial") {
17248
- return {
17249
- object: salvagePartial(options.schema, capturedRaw),
17250
- raw: capturedRaw,
17251
- usage: lastUsage,
17252
- finishReason: "tool_use"
17253
- };
17254
- }
17255
- throw new GenerateObjectError(
17256
- "parse_failed",
17257
- "Schema parse failed after all retries.",
17258
- lastParseError
17259
- );
17260
- } finally {
17261
- await disposeAndDeleteTransient(agent, deps.delete);
17262
- }
17263
- }
17264
- var GenerateObjectError;
17265
- var init_generate_object = __esm({
17266
- "src/generate-object.ts"() {
17267
- init_structured_output_helpers();
17268
- GenerateObjectError = class extends Error {
17269
- name = "GenerateObjectError";
17270
- code;
17271
- cause;
17272
- constructor(code, message, cause) {
17273
- super(message);
17274
- this.code = code;
17275
- if (cause !== void 0) this.cause = cause;
17276
- }
17277
- };
17278
- }
17279
- });
17280
17612
 
17281
17613
  // src/stream-object.ts
17282
17614
  var stream_object_exports = {};
@@ -17332,7 +17664,7 @@ async function* streamObjectImpl(options, deps) {
17332
17664
  }
17333
17665
  }
17334
17666
  const result = await run.wait();
17335
- lastUsage = extractUsage2(result);
17667
+ lastUsage = extractUsage(result);
17336
17668
  if (capturedRaw === void 0) {
17337
17669
  if (result.status === "error" && result.error !== void 0) {
17338
17670
  throw new StreamObjectError(
@@ -17979,6 +18311,7 @@ var init_agent = __esm({
17979
18311
  };
17980
18312
  setAgentFacade({
17981
18313
  create: (options) => Agent.create(options),
18314
+ delete: (agentId) => Agent.delete(agentId),
17982
18315
  prompt: (message, options) => Agent.prompt(message, options),
17983
18316
  get: (agentId) => Agent.get(agentId),
17984
18317
  resume: (agentId, options) => Agent.resume(agentId, options),
@@ -18035,7 +18368,9 @@ var MessageBus = class {
18035
18368
  ...partial,
18036
18369
  from,
18037
18370
  to,
18038
- timestamp: Date.now()
18371
+ timestamp: Date.now(),
18372
+ // SE3 — provenance projection of the sender address (thin view over `from`).
18373
+ origin: { kind: "peer", from }
18039
18374
  };
18040
18375
  handler(message);
18041
18376
  }
@@ -18049,7 +18384,9 @@ var MessageBus = class {
18049
18384
  ...partial,
18050
18385
  from,
18051
18386
  to,
18052
- timestamp: Date.now()
18387
+ timestamp: Date.now(),
18388
+ // SE3 — provenance projection of the sender address (thin view over `from`).
18389
+ origin: { kind: "peer", from }
18053
18390
  };
18054
18391
  return Promise.race([
18055
18392
  Promise.resolve(handler(message)),