flavor-code 1.3.10 → 1.3.12

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.
@@ -12,7 +12,7 @@ import {
12
12
  redactConfig,
13
13
  setProjectMcpServerDisabled,
14
14
  updateProtectedFile
15
- } from "./chunk-IG4Z23CL.js";
15
+ } from "./chunk-JFKRX2KG.js";
16
16
  import {
17
17
  AuditLogger,
18
18
  appendUsageLog,
@@ -1082,6 +1082,231 @@ function packageVersion() {
1082
1082
  throw new Error("package.json with a version field was not found");
1083
1083
  }
1084
1084
 
1085
+ // src/ui/char-width.ts
1086
+ function charWidth(codePoint) {
1087
+ if (codePoint === 8203 || // ZERO WIDTH SPACE
1088
+ codePoint === 8204 || // ZERO WIDTH NON-JOINER
1089
+ codePoint === 8205 || // ZERO WIDTH JOINER
1090
+ codePoint === 65279 || // BOM / ZERO WIDTH NO-BREAK SPACE
1091
+ codePoint >= 768 && codePoint <= 879 || // Combining Diacritical Marks
1092
+ codePoint >= 1155 && codePoint <= 1161 || // Cyrillic combining marks
1093
+ codePoint >= 1425 && codePoint <= 1469 || // Hebrew combining marks
1094
+ codePoint >= 1552 && codePoint <= 1562 || // Arabic combining marks
1095
+ codePoint >= 1611 && codePoint <= 1631 || // Arabic combining marks
1096
+ codePoint >= 1648 && codePoint <= 1648 || // Arabic combining marks
1097
+ codePoint >= 1750 && codePoint <= 1756 || // Arabic combining marks
1098
+ codePoint >= 1759 && codePoint <= 1764 || // Arabic combining marks
1099
+ codePoint >= 1767 && codePoint <= 1768 || // Arabic combining marks
1100
+ codePoint >= 1770 && codePoint <= 1773 || // Arabic combining marks
1101
+ codePoint >= 1809 && codePoint <= 1809 || // Syriac combining marks
1102
+ codePoint >= 1840 && codePoint <= 1866 || // Syriac combining marks
1103
+ codePoint >= 1958 && codePoint <= 1968 || // Thaana combining marks
1104
+ codePoint >= 2304 && codePoint <= 2306 || // Devanagari combining marks
1105
+ codePoint >= 2362 && codePoint <= 2362 || // Devanagari combining marks
1106
+ codePoint >= 2364 && codePoint <= 2364 || // Devanagari combining marks
1107
+ codePoint >= 2369 && codePoint <= 2376 || // Devanagari combining marks
1108
+ codePoint >= 2381 && codePoint <= 2381 || // Devanagari combining marks
1109
+ codePoint >= 2385 && codePoint <= 2391 || // Devanagari combining marks
1110
+ codePoint >= 2402 && codePoint <= 2403 || // Devanagari combining marks
1111
+ codePoint >= 2433 && codePoint <= 2433 || // Bengali combining marks
1112
+ codePoint >= 2492 && codePoint <= 2492 || // Bengali combining marks
1113
+ codePoint >= 2497 && codePoint <= 2500 || // Bengali combining marks
1114
+ codePoint >= 2509 && codePoint <= 2509 || // Bengali combining marks
1115
+ codePoint >= 2530 && codePoint <= 2531 || // Bengali combining marks
1116
+ codePoint >= 2561 && codePoint <= 2562 || // Gurmukhi combining marks
1117
+ codePoint >= 2620 && codePoint <= 2620 || // Gurmukhi combining marks
1118
+ codePoint >= 2625 && codePoint <= 2626 || // Gurmukhi combining marks
1119
+ codePoint >= 2631 && codePoint <= 2632 || // Gurmukhi combining marks
1120
+ codePoint >= 2635 && codePoint <= 2637 || // Gurmukhi combining marks
1121
+ codePoint >= 2672 && codePoint <= 2673 || // Gurmukhi combining marks
1122
+ codePoint >= 2689 && codePoint <= 2690 || // Gujarati combining marks
1123
+ codePoint >= 2748 && codePoint <= 2748 || // Gujarati combining marks
1124
+ codePoint >= 2753 && codePoint <= 2757 || // Gujarati combining marks
1125
+ codePoint >= 2759 && codePoint <= 2760 || // Gujarati combining marks
1126
+ codePoint >= 2765 && codePoint <= 2765 || // Gujarati combining marks
1127
+ codePoint >= 2786 && codePoint <= 2787 || // Gujarati combining marks
1128
+ codePoint >= 2817 && codePoint <= 2817 || // Oriya combining marks
1129
+ codePoint >= 2876 && codePoint <= 2876 || // Oriya combining marks
1130
+ codePoint >= 2879 && codePoint <= 2879 || // Oriya combining marks
1131
+ codePoint >= 2881 && codePoint <= 2883 || // Oriya combining marks
1132
+ codePoint >= 2893 && codePoint <= 2893 || // Oriya combining marks
1133
+ codePoint >= 2902 && codePoint <= 2902 || // Oriya combining marks
1134
+ codePoint >= 2946 && codePoint <= 2946 || // Tamil combining marks
1135
+ codePoint >= 3008 && codePoint <= 3008 || // Tamil combining marks
1136
+ codePoint >= 3021 && codePoint <= 3021 || // Tamil combining marks
1137
+ codePoint >= 3134 && codePoint <= 3136 || // Telugu combining marks
1138
+ codePoint >= 3142 && codePoint <= 3144 || // Telugu combining marks
1139
+ codePoint >= 3146 && codePoint <= 3149 || // Telugu combining marks
1140
+ codePoint >= 3157 && codePoint <= 3158 || // Telugu combining marks
1141
+ codePoint >= 3260 && codePoint <= 3260 || // Kannada combining marks
1142
+ codePoint >= 3263 && codePoint <= 3263 || // Kannada combining marks
1143
+ codePoint >= 3270 && codePoint <= 3270 || // Kannada combining marks
1144
+ codePoint >= 3276 && codePoint <= 3277 || // Kannada combining marks
1145
+ codePoint >= 3298 && codePoint <= 3299 || // Kannada combining marks
1146
+ codePoint >= 3393 && codePoint <= 3395 || // Malayalam combining marks
1147
+ codePoint >= 3405 && codePoint <= 3405 || // Malayalam combining marks
1148
+ codePoint >= 3530 && codePoint <= 3530 || // Sinhala combining marks
1149
+ codePoint >= 3538 && codePoint <= 3540 || // Sinhala combining marks
1150
+ codePoint >= 3542 && codePoint <= 3542 || // Sinhala combining marks
1151
+ codePoint >= 3633 && codePoint <= 3633 || // Thai combining marks
1152
+ codePoint >= 3636 && codePoint <= 3642 || // Thai combining marks
1153
+ codePoint >= 3655 && codePoint <= 3662 || // Thai combining marks
1154
+ codePoint >= 3761 && codePoint <= 3761 || // Lao combining marks
1155
+ codePoint >= 3764 && codePoint <= 3769 || // Lao combining marks
1156
+ codePoint >= 3771 && codePoint <= 3772 || // Lao combining marks
1157
+ codePoint >= 3784 && codePoint <= 3789 || // Lao combining marks
1158
+ codePoint >= 3864 && codePoint <= 3865 || // Tibetan combining marks
1159
+ codePoint >= 3893 && codePoint <= 3893 || // Tibetan combining marks
1160
+ codePoint >= 3895 && codePoint <= 3895 || // Tibetan combining marks
1161
+ codePoint >= 3897 && codePoint <= 3897 || // Tibetan combining marks
1162
+ codePoint >= 3953 && codePoint <= 3966 || // Tibetan combining marks
1163
+ codePoint >= 3968 && codePoint <= 3972 || // Tibetan combining marks
1164
+ codePoint >= 3974 && codePoint <= 3975 || // Tibetan combining marks
1165
+ codePoint >= 3984 && codePoint <= 3991 || // Tibetan combining marks
1166
+ codePoint >= 3993 && codePoint <= 4028 || // Tibetan combining marks
1167
+ codePoint >= 4038 && codePoint <= 4038 || // Tibetan combining marks
1168
+ codePoint >= 4146 && codePoint <= 4151 || // Myanmar combining marks
1169
+ codePoint >= 4153 && codePoint <= 4154 || // Myanmar combining marks
1170
+ codePoint >= 4157 && codePoint <= 4158 || // Myanmar combining marks
1171
+ codePoint >= 4184 && codePoint <= 4185 || // Myanmar combining marks
1172
+ codePoint >= 4190 && codePoint <= 4192 || // Myanmar combining marks
1173
+ codePoint >= 4209 && codePoint <= 4212 || // Myanmar combining marks
1174
+ codePoint >= 4226 && codePoint <= 4226 || // Myanmar combining marks
1175
+ codePoint >= 4229 && codePoint <= 4230 || // Myanmar combining marks
1176
+ codePoint >= 4237 && codePoint <= 4237 || // Myanmar combining marks
1177
+ codePoint >= 4957 && codePoint <= 4959 || // Ethiopic combining marks
1178
+ codePoint >= 5906 && codePoint <= 5908 || // Tagalog combining marks
1179
+ codePoint >= 5938 && codePoint <= 5940 || // Hanunoo combining marks
1180
+ codePoint >= 5970 && codePoint <= 5971 || // Buhid combining marks
1181
+ codePoint >= 6002 && codePoint <= 6003 || // Tagbanwa combining marks
1182
+ codePoint >= 6068 && codePoint <= 6069 || // Khmer combining marks
1183
+ codePoint >= 6071 && codePoint <= 6077 || // Khmer combining marks
1184
+ codePoint >= 6086 && codePoint <= 6086 || // Khmer combining marks
1185
+ codePoint >= 6089 && codePoint <= 6099 || // Khmer combining marks
1186
+ codePoint >= 6109 && codePoint <= 6109 || // Khmer combining marks
1187
+ codePoint >= 6155 && codePoint <= 6157 || // Mongolian combining marks
1188
+ codePoint >= 6313 && codePoint <= 6313 || // Mongolian combining marks
1189
+ codePoint >= 6432 && codePoint <= 6434 || // Limbu combining marks
1190
+ codePoint >= 6439 && codePoint <= 6440 || // Limbu combining marks
1191
+ codePoint >= 6450 && codePoint <= 6450 || // Limbu combining marks
1192
+ codePoint >= 6457 && codePoint <= 6459 || // Limbu combining marks
1193
+ codePoint >= 6679 && codePoint <= 6680 || // Buginese combining marks
1194
+ codePoint >= 6912 && codePoint <= 6915 || // Balinese combining marks
1195
+ codePoint >= 6964 && codePoint <= 6964 || // Balinese combining marks
1196
+ codePoint >= 6966 && codePoint <= 6970 || // Balinese combining marks
1197
+ codePoint >= 6972 && codePoint <= 6972 || // Balinese combining marks
1198
+ codePoint >= 6978 && codePoint <= 6978 || // Balinese combining marks
1199
+ codePoint >= 7019 && codePoint <= 7027 || // Balinese combining marks
1200
+ codePoint >= 7616 && codePoint <= 7679 || // Combining Diacritical Marks Supplement
1201
+ codePoint >= 8400 && codePoint <= 8432 || // Combining Diacritical Marks for Symbols
1202
+ codePoint >= 11503 && codePoint <= 11505 || // Coptic combining marks
1203
+ codePoint >= 11647 && codePoint <= 11647 || // Tifinagh combining marks
1204
+ codePoint >= 11744 && codePoint <= 11775 || // Cyrillic Extended-A combining marks
1205
+ codePoint >= 42607 && codePoint <= 42610 || // Cyrillic Extended-B combining marks
1206
+ codePoint >= 42612 && codePoint <= 42621 || // Cyrillic Extended-B combining marks
1207
+ codePoint >= 42654 && codePoint <= 42655 || // Cyrillic Extended-B combining marks
1208
+ codePoint >= 42736 && codePoint <= 42737 || // Bamum combining marks
1209
+ codePoint >= 43010 && codePoint <= 43010 || // Syloti Nagri combining marks
1210
+ codePoint >= 43014 && codePoint <= 43014 || // Syloti Nagri combining marks
1211
+ codePoint >= 43019 && codePoint <= 43019 || // Syloti Nagri combining marks
1212
+ codePoint >= 43045 && codePoint <= 43046 || // Syloti Nagri combining marks
1213
+ codePoint >= 43204 && codePoint <= 43204 || // Saurashtra combining marks
1214
+ codePoint >= 43232 && codePoint <= 43249 || // Devanagari Extended combining marks
1215
+ codePoint >= 43302 && codePoint <= 43309 || // Kayah Li combining marks
1216
+ codePoint >= 43335 && codePoint <= 43345 || // Rejang combining marks
1217
+ codePoint >= 43392 && codePoint <= 43394 || // Javanese combining marks
1218
+ codePoint >= 43443 && codePoint <= 43443 || // Javanese combining marks
1219
+ codePoint >= 43446 && codePoint <= 43449 || // Javanese combining marks
1220
+ codePoint >= 43452 && codePoint <= 43452 || // Javanese combining marks
1221
+ codePoint >= 43561 && codePoint <= 43566 || // Cham combining marks
1222
+ codePoint >= 43569 && codePoint <= 43570 || // Cham combining marks
1223
+ codePoint >= 43573 && codePoint <= 43574 || // Cham combining marks
1224
+ codePoint >= 43587 && codePoint <= 43587 || // Cham combining marks
1225
+ codePoint >= 43596 && codePoint <= 43596 || // Cham combining marks
1226
+ codePoint >= 43696 && codePoint <= 43696 || // Tai Viet combining marks
1227
+ codePoint >= 43698 && codePoint <= 43700 || // Tai Viet combining marks
1228
+ codePoint >= 43703 && codePoint <= 43704 || // Tai Viet combining marks
1229
+ codePoint >= 43710 && codePoint <= 43711 || // Tai Viet combining marks
1230
+ codePoint >= 43713 && codePoint <= 43713 || // Tai Viet combining marks
1231
+ codePoint >= 44005 && codePoint <= 44005 || // Meetei Mayek combining marks
1232
+ codePoint >= 44008 && codePoint <= 44008 || // Meetei Mayek combining marks
1233
+ codePoint >= 44013 && codePoint <= 44013 || // Meetei Mayek combining marks
1234
+ codePoint >= 64286 && codePoint <= 64286 || // Hebrew combining marks
1235
+ codePoint >= 65024 && codePoint <= 65039 || // Variation Selectors
1236
+ codePoint >= 65056 && codePoint <= 65071 || // Combining Half Marks
1237
+ codePoint >= 917760 && codePoint <= 917999) {
1238
+ return 0;
1239
+ }
1240
+ if (codePoint >= 4352 && codePoint <= 4447 || // Hangul Jamo
1241
+ codePoint >= 9001 && codePoint <= 9002 || // Left/Right-pointing angle bracket
1242
+ codePoint >= 11904 && codePoint <= 12350 || // CJK Radicals Supplement, Kangxi Radicals, CJK Symbols
1243
+ codePoint >= 12352 && codePoint <= 13247 || // Hiragana, Katakana, Bopomofo, Hangul Compatibility, Kanbun, CJK Strokes, Enclosed CJK
1244
+ codePoint >= 13312 && codePoint <= 19903 || // CJK Unified Ideographs Extension A
1245
+ codePoint >= 19968 && codePoint <= 42191 || // CJK Unified Ideographs, Yi Syllables, Yi Radicals
1246
+ codePoint >= 43360 && codePoint <= 43388 || // Hangul Jamo Extended-A
1247
+ codePoint >= 44032 && codePoint <= 55203 || // Hangul Syllables
1248
+ codePoint >= 63744 && codePoint <= 64255 || // CJK Compatibility Ideographs
1249
+ codePoint >= 65040 && codePoint <= 65049 || // Vertical forms
1250
+ codePoint >= 65072 && codePoint <= 65135 || // CJK Compatibility Forms, Small Form Variants
1251
+ codePoint >= 65281 && codePoint <= 65376 || // Fullwidth Forms
1252
+ codePoint >= 65504 && codePoint <= 65510 || // Fullwidth Signs
1253
+ codePoint >= 110592 && codePoint <= 111359 || // Kana Supplement, Kana Extended-A, Small Kana Extension
1254
+ codePoint >= 126980 && codePoint <= 126980 || // Mahjong tile
1255
+ codePoint >= 127183 && codePoint <= 127183 || // Playing card
1256
+ codePoint >= 127232 && codePoint <= 129535 || // Enclosed Alphanumeric Supplement, Emoticons, Transport, etc.
1257
+ codePoint >= 129536 && codePoint <= 129647 || // Chess Symbols
1258
+ codePoint >= 129648 && codePoint <= 129791 || // Symbols and Pictographs Extended-A
1259
+ codePoint >= 131072 && codePoint <= 196605 || // CJK Unified Ideographs Extension B–G, CJK Compatibility Supplement
1260
+ codePoint >= 196608 && codePoint <= 262141) {
1261
+ return 2;
1262
+ }
1263
+ return 1;
1264
+ }
1265
+
1266
+ // src/ui/thinking-line.ts
1267
+ var THINKING_SCROLL_CELLS_PER_SEC = 16;
1268
+ var THINKING_EASE = 0.18;
1269
+ var THINKING_MAX_STEP_MS = 250;
1270
+ var THINKING_MAX_STORED_CHARS = 4e3;
1271
+ function normalizeThinkingText(text) {
1272
+ return text.replace(/\s+/gu, " ").trim();
1273
+ }
1274
+ function thinkingDisplayWidth(text) {
1275
+ let width = 0;
1276
+ for (const character of text) width += charWidth(character.codePointAt(0) ?? 32);
1277
+ return width;
1278
+ }
1279
+ function sliceThinkingByWidth(text, startCell, cellCount) {
1280
+ let out = "";
1281
+ let cell = 0;
1282
+ for (const character of text) {
1283
+ const w = charWidth(character.codePointAt(0) ?? 32);
1284
+ if (cell + w > startCell && cell < startCell + cellCount) out += character;
1285
+ cell += w;
1286
+ if (cell >= startCell + cellCount) break;
1287
+ }
1288
+ return out;
1289
+ }
1290
+ function thinkingWindow(text, previousStart, options) {
1291
+ const normalized = normalizeThinkingText(text);
1292
+ const width = Math.max(1, Math.floor(options.width));
1293
+ const total = thinkingDisplayWidth(normalized);
1294
+ if (total <= width) return { text: normalized, start: 0 };
1295
+ const maxStart = total - width;
1296
+ const from = Math.min(Math.max(0, previousStart), maxStart);
1297
+ const cellsPerSecond = options.cellsPerSecond ?? THINKING_SCROLL_CELLS_PER_SEC;
1298
+ const ease = options.ease ?? THINKING_EASE;
1299
+ const dt = Math.max(0, Math.min(options.dtMs, THINKING_MAX_STEP_MS));
1300
+ const lag = maxStart - from;
1301
+ const step = Math.max(cellsPerSecond * dt / 1e3, lag * ease);
1302
+ const start = Math.min(maxStart, Math.floor(from + step));
1303
+ return { text: sliceThinkingByWidth(normalized, start, width), start };
1304
+ }
1305
+ function appendThinkingText(previous, delta) {
1306
+ const next = (previous ?? "") + delta;
1307
+ return next.length > THINKING_MAX_STORED_CHARS ? next.slice(-THINKING_MAX_STORED_CHARS) : next;
1308
+ }
1309
+
1085
1310
  // src/ui/transcript.ts
1086
1311
  function createTranscriptState() {
1087
1312
  return { completed: [], nextId: 1 };
@@ -1178,6 +1403,9 @@ function transcriptReducer(state, action) {
1178
1403
  if (event.type === "text") {
1179
1404
  return { ...state, active: addText(withoutModelActivity(state.active), event.text) };
1180
1405
  }
1406
+ if (event.type === "thinking") {
1407
+ return { ...state, active: attachThinking(state.active, event.text) };
1408
+ }
1181
1409
  if (event.type === "tool-start") return upsertStatus({ ...state, active: withoutModelActivity(state.active) }, {
1182
1410
  kind: "status",
1183
1411
  id: `tool:${event.id}`,
@@ -1478,6 +1706,18 @@ function finishActive(state) {
1478
1706
  ...state.taskSnapshot === void 0 ? {} : { taskSnapshot: state.taskSnapshot }
1479
1707
  };
1480
1708
  }
1709
+ function attachThinking(turn, text) {
1710
+ const blocks = [...turn.blocks];
1711
+ const index = blocks.findIndex((block2) => block2.kind === "status" && block2.activity === "model" && block2.state === "running");
1712
+ if (index < 0) return turn;
1713
+ const block = blocks[index];
1714
+ if (block === void 0 || block.kind !== "status") return turn;
1715
+ blocks[index] = {
1716
+ ...block,
1717
+ thinkingText: appendThinkingText(block.thinkingText, text)
1718
+ };
1719
+ return { ...turn, blocks };
1720
+ }
1481
1721
  function withoutModelActivity(turn, id) {
1482
1722
  const blocks = turn.blocks.filter((block) => block.kind !== "status" || block.activity !== "model" || id !== void 0 && block.id !== id);
1483
1723
  if (blocks.length === turn.blocks.length) return turn;
@@ -2996,7 +3236,8 @@ var MVP_COMMANDS = [
2996
3236
  "fork",
2997
3237
  "pals",
2998
3238
  "chat",
2999
- "co-work"
3239
+ "co-work",
3240
+ "tool"
3000
3241
  ];
3001
3242
  var COMMAND_DESCRIPTIONS = {
3002
3243
  model: "Switch the active model",
@@ -3034,16 +3275,24 @@ var COMMAND_DESCRIPTIONS = {
3034
3275
  fork: "Continue context from a prior session node",
3035
3276
  pals: "List, rename, or inspect active Flavor pals",
3036
3277
  chat: "Send a task to another Flavor pal",
3037
- "co-work": "Coordinate a shared goal with another Flavor pal"
3278
+ "co-work": "Coordinate a shared goal with another Flavor pal",
3279
+ tool: "Run a registered managed tool with a JSON object"
3038
3280
  };
3039
- function parseSlashCommand(input, dynamicCommands = [], skillCommands = []) {
3281
+ function parseSlashCommand(input, dynamicCommands = [], skillCommands = [], managedTools = []) {
3040
3282
  const trimmed = input.trim();
3041
3283
  if (!trimmed.startsWith("/")) return null;
3042
- const [rawName = "", ...args] = trimmed.slice(1).split(/\s+/);
3284
+ const match = /^(\S+)(?:\s+([\s\S]*))?$/u.exec(trimmed.slice(1));
3285
+ const rawName = match?.[1] ?? "";
3286
+ const rawArguments = match?.[2] ?? "";
3287
+ const args = rawArguments.length === 0 ? [] : rawArguments.split(/\s+/u);
3043
3288
  const name = rawName.toLowerCase();
3044
3289
  if (!MVP_COMMANDS.includes(name) && dynamicCommands.includes(name)) {
3045
3290
  return { name: "plugin", command: name, args };
3046
3291
  }
3292
+ if (!MVP_COMMANDS.includes(name)) {
3293
+ const managedTool = managedTools.find((tool) => tool.toLowerCase() === name);
3294
+ if (managedTool !== void 0) return { name: "managed-tool", tool: managedTool, input: rawArguments };
3295
+ }
3047
3296
  if (!MVP_COMMANDS.includes(name) && skillCommands.includes(name)) {
3048
3297
  return { name: "skill", skill: name, prompt: args.join(" ") };
3049
3298
  }
@@ -3065,6 +3314,15 @@ function parseSlashCommand(input, dynamicCommands = [], skillCommands = []) {
3065
3314
  }
3066
3315
  return { name, mode: normalized };
3067
3316
  }
3317
+ if (name === "tool") {
3318
+ const [requested] = args;
3319
+ const managedTool = requested === void 0 ? void 0 : managedTools.find((candidate) => candidate.toLowerCase() === requested.toLowerCase());
3320
+ if (managedTool === void 0) {
3321
+ return { name: "invalid", command: name, message: "Use /tool <registered-tool> [JSON object]." };
3322
+ }
3323
+ const inputStart = rawArguments.search(/\s/u);
3324
+ return { name: "managed-tool", tool: managedTool, input: inputStart < 0 ? "" : rawArguments.slice(inputStart).trimStart() };
3325
+ }
3068
3326
  if (name === "audit") {
3069
3327
  const toolFilter = args.length > 0 ? args.join(" ") : void 0;
3070
3328
  return { name, toolFilter };
@@ -3292,6 +3550,7 @@ var HELP = [
3292
3550
  "/review [focus] review uncommitted changes before committing",
3293
3551
  "/evolve <signals|suggest|improve <id>|verify <name>|reload <name>|test|revert <name>|done <id>> self-improvement loop",
3294
3552
  "/mcp [status|tools|reconnect|enable|disable] manage MCP servers",
3553
+ "/tool <registered-tool> [JSON object] run a registered tool (or use /<tool-name>)",
3295
3554
  "/ide show VS Code connection and cursor/selection",
3296
3555
  "/pals [--verbose|rename <alias>|info <alias-or-uuid>]",
3297
3556
  "/chat <alias-or-uuid> <goal> send a task that starts on the receiving pal",
@@ -3563,7 +3822,12 @@ var FlavorSession = class {
3563
3822
  } catch {
3564
3823
  }
3565
3824
  }
3566
- const command = parseSlashCommand(prompt, this.#services.pluginCommands().map(({ name }) => name), skillNames);
3825
+ const command = parseSlashCommand(
3826
+ prompt,
3827
+ this.#services.pluginCommands().map(({ name }) => name),
3828
+ skillNames,
3829
+ this.#services.managedToolCommands().map(({ name }) => name)
3830
+ );
3567
3831
  if (command !== null) await this.#dispatch(command, controller.signal);
3568
3832
  else for await (const event of this.#services.run(prompt, controller.signal, {
3569
3833
  getSteeringMessages: () => this.#drainMessages("steer", true).map((item) => item.text),
@@ -3665,6 +3929,8 @@ var FlavorSession = class {
3665
3929
  this.#notice(`Main permissions set to ${command.mode}. Child approvals use bubble mode unless plan mode is active.`);
3666
3930
  } else if (command.name === "plugin") {
3667
3931
  this.#notice(format(await this.#services.runPluginCommand(command.command, command.args, signal)));
3932
+ } else if (command.name === "managed-tool") {
3933
+ this.#notice(format(await this.#services.runManagedTool(command.tool, command.input, signal)));
3668
3934
  } else if (command.name === "skill") {
3669
3935
  for await (const event of this.#services.runSkill(command.skill, command.prompt, signal)) this.#services.output(event);
3670
3936
  } else if (command.name === "loop") {
@@ -6315,7 +6581,12 @@ function providerValidMessages(input) {
6315
6581
  const calls = original.toolCalls.filter((call) => call.id && call.name && availableResults.has(call.id));
6316
6582
  calls.forEach((call) => announced.add(call.id));
6317
6583
  if (!original.content && calls.length === 0) continue;
6318
- output.push({ role: "assistant", content: original.content, ...calls.length === 0 ? {} : { toolCalls: calls.map((call) => ({ ...call })) } });
6584
+ output.push({
6585
+ role: "assistant",
6586
+ content: original.content,
6587
+ ...calls.length === 0 ? {} : { toolCalls: calls.map((call) => ({ ...call })) },
6588
+ ...original.thinkingBlocks === void 0 ? {} : { thinkingBlocks: original.thinkingBlocks.map((block) => ({ ...block })) }
6589
+ });
6319
6590
  continue;
6320
6591
  }
6321
6592
  if (original.role === "tool") {
@@ -6536,9 +6807,10 @@ function withStructuredOutput(options) {
6536
6807
  throw new Error("Structured output retry delays must be non-negative integers");
6537
6808
  }
6538
6809
  }
6539
- const tool = modelToolFromZod(options.name, options.description, options.schema);
6810
+ const generatedTool = options.modelInputSchema === void 0 ? modelToolFromZod(options.name, options.description, options.schema) : { name: options.name, description: options.description, inputSchema: options.modelInputSchema };
6811
+ const tool = options.modelStrict === void 0 ? generatedTool : { ...generatedTool, strict: options.modelStrict };
6540
6812
  const maxAttempts = retry.maxRetries + 1;
6541
- const jsonSchema = tool.inputSchema;
6813
+ const validationSchema = jsonSchemaFromZod(options.schema);
6542
6814
  const model = {
6543
6815
  async *stream(request) {
6544
6816
  let candidate;
@@ -6611,7 +6883,7 @@ function withStructuredOutput(options) {
6611
6883
  }
6612
6884
  }
6613
6885
  if (candidateCount === 1 && candidate !== null && typeof candidate === "object") {
6614
- candidate = coerceByJsonSchema(candidate, jsonSchema);
6886
+ candidate = coerceByJsonSchema(candidate, validationSchema);
6615
6887
  }
6616
6888
  if (candidateCount !== 1) {
6617
6889
  attemptError = {
@@ -6683,7 +6955,13 @@ function withStructuredOutput(options) {
6683
6955
  return model;
6684
6956
  }
6685
6957
  function strictJsonSchema(schema) {
6686
- return ensureStrictSchema(z7.toJSONSchema(schema));
6958
+ return strictJsonSchemaObject(jsonSchemaFromZod(schema));
6959
+ }
6960
+ function jsonSchemaFromZod(schema) {
6961
+ return z7.toJSONSchema(schema);
6962
+ }
6963
+ function strictJsonSchemaObject(schema) {
6964
+ return ensureStrictSchema(schema);
6687
6965
  }
6688
6966
  function extractJsonObject(text) {
6689
6967
  const trimmed = text.trim();
@@ -6731,6 +7009,7 @@ function coerceByJsonSchema(value, schema) {
6731
7009
  const node = schema;
6732
7010
  const branches = [
6733
7011
  ...Array.isArray(node.anyOf) ? node.anyOf : [],
7012
+ ...Array.isArray(node.oneOf) ? node.oneOf : [],
6734
7013
  ...Array.isArray(node.allOf) ? node.allOf : []
6735
7014
  ].filter((branch) => branch !== null && typeof branch === "object");
6736
7015
  const types = [];
@@ -6750,40 +7029,108 @@ function coerceByJsonSchema(value, schema) {
6750
7029
  if (lowered === "true") return true;
6751
7030
  if (lowered === "false") return false;
6752
7031
  }
7032
+ if (types.includes("object") && !types.includes("string") && typeof value === "string") {
7033
+ const trimmed = value.trim();
7034
+ if (trimmed.startsWith("{")) {
7035
+ try {
7036
+ const parsed = JSON.parse(trimmed);
7037
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
7038
+ return coerceByJsonSchema(parsed, node);
7039
+ }
7040
+ } catch {
7041
+ }
7042
+ }
7043
+ }
7044
+ if (types.includes("array") && !Array.isArray(value) && value !== null && value !== void 0 && !types.some((type) => matchesJsonSchemaType(value, type))) {
7045
+ const arraySchema = [node, ...branches].find((candidate) => {
7046
+ const type = candidate.type;
7047
+ return type === "array" || Array.isArray(type) && type.includes("array");
7048
+ });
7049
+ if (typeof value === "string" && value.trim().startsWith("[")) {
7050
+ try {
7051
+ const parsed = JSON.parse(value.trim());
7052
+ if (Array.isArray(parsed)) return coerceByJsonSchema(parsed, arraySchema ?? node);
7053
+ } catch {
7054
+ }
7055
+ }
7056
+ return [arraySchema?.items === void 0 ? value : coerceByJsonSchema(value, arraySchema.items)];
7057
+ }
6753
7058
  if (value !== null && typeof value === "object" && !Array.isArray(value)) {
6754
- const properties = node.properties ?? branches.find((branch) => branch.properties)?.properties;
7059
+ const objectSchema = [node, ...branches].find((candidate) => candidate.type === "object" || candidate.properties !== void 0);
7060
+ const properties = objectSchema?.properties;
6755
7061
  if (properties !== void 0) {
6756
7062
  const output = {};
7063
+ const required2 = new Set(Array.isArray(objectSchema?.required) ? objectSchema.required : []);
6757
7064
  for (const [key, child] of Object.entries(value)) {
6758
- output[key] = properties[key] !== void 0 ? coerceByJsonSchema(child, properties[key]) : child;
7065
+ const childSchema = properties[key];
7066
+ if (child === null && childSchema !== void 0 && !required2.has(key) && !jsonSchemaAllowsNull(childSchema)) {
7067
+ continue;
7068
+ }
7069
+ output[key] = childSchema !== void 0 ? coerceByJsonSchema(child, childSchema) : child;
6759
7070
  }
6760
7071
  return output;
6761
7072
  }
6762
7073
  }
6763
- if (types.includes("array") && Array.isArray(value) && node.items !== void 0) {
6764
- return value.map((item) => coerceByJsonSchema(item, node.items));
7074
+ if (types.includes("array") && Array.isArray(value)) {
7075
+ const arraySchema = [node, ...branches].find((candidate) => {
7076
+ const type = candidate.type;
7077
+ return type === "array" || Array.isArray(type) && type.includes("array");
7078
+ });
7079
+ if (arraySchema?.items !== void 0) {
7080
+ return value.map((item) => coerceByJsonSchema(item, arraySchema.items));
7081
+ }
6765
7082
  }
6766
7083
  return value;
6767
7084
  }
7085
+ function matchesJsonSchemaType(value, type) {
7086
+ if (type === "null") return value === null;
7087
+ if (type === "array") return Array.isArray(value);
7088
+ if (type === "object") return value !== null && typeof value === "object" && !Array.isArray(value);
7089
+ if (type === "integer") return typeof value === "number" && Number.isInteger(value);
7090
+ if (type === "number") return typeof value === "number";
7091
+ return typeof value === type;
7092
+ }
7093
+ function jsonSchemaAllowsNull(schema) {
7094
+ if (schema === null || typeof schema !== "object") return false;
7095
+ const node = schema;
7096
+ if (node.type === "null" || Array.isArray(node.type) && node.type.includes("null")) return true;
7097
+ return [node.anyOf, node.oneOf].some((branches) => Array.isArray(branches) && branches.some((branch) => jsonSchemaAllowsNull(branch)));
7098
+ }
6768
7099
  function modelToolFromZod(name, description, schema) {
6769
7100
  return { name, description, inputSchema: strictJsonSchema(schema) };
6770
7101
  }
6771
7102
  function ensureStrictSchema(schema) {
7103
+ const output = { ...schema };
7104
+ for (const keyword of ["anyOf", "oneOf", "allOf", "prefixItems"]) {
7105
+ const branches = schema[keyword];
7106
+ if (Array.isArray(branches)) {
7107
+ output[keyword] = branches.map((branch) => typeof branch === "object" && branch !== null ? ensureStrictSchema(branch) : branch);
7108
+ }
7109
+ }
7110
+ if (typeof schema.items === "object" && schema.items !== null) {
7111
+ output.items = ensureStrictSchema(schema.items);
7112
+ }
7113
+ for (const keyword of ["$defs", "definitions"]) {
7114
+ const definitions = schema[keyword];
7115
+ if (typeof definitions === "object" && definitions !== null && !Array.isArray(definitions)) {
7116
+ output[keyword] = Object.fromEntries(Object.entries(definitions).map(([key, definition]) => [
7117
+ key,
7118
+ typeof definition === "object" && definition !== null ? ensureStrictSchema(definition) : definition
7119
+ ]));
7120
+ }
7121
+ }
6772
7122
  if (schema.type !== "object" || typeof schema.properties !== "object" || schema.properties === null) {
6773
- return schema;
7123
+ return output;
6774
7124
  }
6775
- const required2 = Array.isArray(schema.required) ? [...schema.required] : [];
6776
- const requiredSet = new Set(required2);
7125
+ const requiredSet = new Set(Array.isArray(schema.required) ? schema.required : []);
6777
7126
  const properties = {};
6778
7127
  for (const [key, value] of Object.entries(schema.properties)) {
6779
7128
  const child = typeof value === "object" && value !== null ? ensureStrictSchema(value) : value;
6780
- if (requiredSet.has(key)) properties[key] = child;
6781
- else {
6782
- properties[key] = { anyOf: [child, { type: "null" }] };
6783
- requiredSet.add(key);
6784
- }
7129
+ if (requiredSet.has(key) || jsonSchemaAllowsNull(child)) properties[key] = child;
7130
+ else properties[key] = { anyOf: [child, { type: "null" }] };
7131
+ requiredSet.add(key);
6785
7132
  }
6786
- return { ...schema, additionalProperties: false, required: [...requiredSet], properties };
7133
+ return { ...output, additionalProperties: false, required: [...requiredSet], properties };
6787
7134
  }
6788
7135
  function repairMessages(messages, tool, original, candidate, error) {
6789
7136
  const details = [
@@ -6962,6 +7309,7 @@ var AgentLoop = class {
6962
7309
  }
6963
7310
  let assistantText = "";
6964
7311
  const collectedToolCalls = [];
7312
+ const collectedThinking = [];
6965
7313
  let completed = false;
6966
7314
  let reactiveRetried = false;
6967
7315
  let attempt = 1;
@@ -6999,6 +7347,7 @@ var AgentLoop = class {
6999
7347
  }
7000
7348
  assistantText = "";
7001
7349
  collectedToolCalls.length = 0;
7350
+ collectedThinking.length = 0;
7002
7351
  completed = false;
7003
7352
  let terminalError;
7004
7353
  let providerError = false;
@@ -7019,6 +7368,10 @@ var AgentLoop = class {
7019
7368
  assistantText += event.text;
7020
7369
  accumulatedText += event.text;
7021
7370
  yield event;
7371
+ } else if (event.type === "thinking") {
7372
+ yield event;
7373
+ } else if (event.type === "thinking-block") {
7374
+ collectedThinking.push({ text: event.text, ...event.signature === void 0 ? {} : { signature: event.signature } });
7022
7375
  } else if (event.type === "tool-call") {
7023
7376
  collectedToolCalls.push({ kind: "valid", id: event.id, name: event.name, input: event.input });
7024
7377
  } else if (event.type === "invalid-tool-call") {
@@ -7153,19 +7506,11 @@ var AgentLoop = class {
7153
7506
  });
7154
7507
  continue;
7155
7508
  }
7156
- const validation = collected.kind === "valid" ? this.#options.runtime.validate(collected) : { ok: false, error: collected.error };
7509
+ const validation = collected.kind === "valid" ? this.#options.runtime.normalize(collected) : { ok: false, error: collected.error };
7157
7510
  if (validation.ok) {
7158
7511
  toolCalls.push({ id: collected.id, name: collected.name, input: validation.input });
7159
7512
  continue;
7160
7513
  }
7161
- if (collected.kind === "valid") {
7162
- const coerced = coerceByJsonSchema(collected.input, strictJsonSchema(definition.inputSchema));
7163
- const revalidation = this.#options.runtime.validate({ ...collected, input: coerced });
7164
- if (revalidation.ok) {
7165
- toolCalls.push({ id: collected.id, name: collected.name, input: revalidation.input });
7166
- continue;
7167
- }
7168
- }
7169
7514
  const repairModelId = this.#options.fallbackModelId ?? this.#options.modelId;
7170
7515
  const invalidOutput = collected.kind === "invalid" ? collected.rawInput : serializeToolInput(collected.input);
7171
7516
  const structured = withStructuredOutput({
@@ -7174,6 +7519,8 @@ var AgentLoop = class {
7174
7519
  name: definition.name,
7175
7520
  description: definition.description,
7176
7521
  schema: definition.inputSchema,
7522
+ ...definition.modelInputSchema === void 0 ? {} : { modelInputSchema: definition.modelInputSchema },
7523
+ ...definition.modelStrict === void 0 ? {} : { modelStrict: definition.modelStrict },
7177
7524
  beforeAttempt: async ({ attempt: repairAttempt, maxAttempts: repairMaxAttempts, messageCount }) => {
7178
7525
  const before = await this.#options.hooks.emit({
7179
7526
  version: 1,
@@ -7372,7 +7719,8 @@ var AgentLoop = class {
7372
7719
  const assistantMessage = {
7373
7720
  role: "assistant",
7374
7721
  content: assistantText,
7375
- toolCalls: toolCalls.map(({ id, name, input }) => ({ id, name, input }))
7722
+ toolCalls: toolCalls.map(({ id, name, input }) => ({ id, name, input })),
7723
+ ...collectedThinking.length === 0 ? {} : { thinkingBlocks: collectedThinking.map((block) => ({ ...block })) }
7376
7724
  };
7377
7725
  this.#options.context.appendMany([assistantMessage, ...stagedMessages]);
7378
7726
  for (const { call, result } of stagedResults) {
@@ -7654,12 +8002,24 @@ var ToolRuntime = class {
7654
8002
  throw error;
7655
8003
  }
7656
8004
  }
8005
+ /**
8006
+ * Validates a call and applies the same conservative provider-argument
8007
+ * normalization used by the agent loop before falling back to repair.
8008
+ */
8009
+ normalize(call) {
8010
+ const validation = this.validate(call);
8011
+ if (validation.ok || validation.error.code === "unknown_tool") return validation;
8012
+ const tool = this.#tools.get(call.name);
8013
+ if (tool === void 0) return validation;
8014
+ const input = coerceByJsonSchema(call.input, jsonSchemaFromZod(tool.inputSchema));
8015
+ return this.validate({ ...call, input });
8016
+ }
7657
8017
  async #execute(call, context) {
7658
8018
  const tool = this.#tools.get(call.name);
7659
8019
  if (tool === void 0) return { ok: false, error: { code: "unknown_tool", message: `Unknown tool: ${call.name}` } };
7660
8020
  const signal = context.signal ?? new AbortController().signal;
7661
8021
  const toolCallId = call.id ?? randomUUID7();
7662
- const validation = this.validate(call);
8022
+ const validation = this.normalize(call);
7663
8023
  if (!validation.ok) {
7664
8024
  return this.#fail(toolCallId, call.name, call.input, context.agent, validation.error.code, validation.error.message);
7665
8025
  }
@@ -9388,6 +9748,7 @@ var PluginHost = class {
9388
9748
  description: contribution.description,
9389
9749
  inputSchema: z13.unknown(),
9390
9750
  ...contribution.modelInputSchema === void 0 ? {} : { modelInputSchema: contribution.modelInputSchema },
9751
+ ...contribution.modelInputSchema === void 0 ? {} : { modelStrict: false },
9391
9752
  ...contribution.readOnly === void 0 ? {} : { readOnly: contribution.readOnly },
9392
9753
  paths: () => [],
9393
9754
  execute: (input, _signal, toolContext) => session.invoke("tool", contribution.name, [
@@ -12616,6 +12977,7 @@ var CLAUDE_CLIENT_HEADERS = {
12616
12977
  "x-app": "cli"
12617
12978
  };
12618
12979
  var DEFAULT_MAX_OUTPUT_TOKENS = 32768;
12980
+ var DEFAULT_THINKING_BUDGET = 8192;
12619
12981
  var MAX_CACHE_MARKERS = 4;
12620
12982
  function collectCacheMarkers(system, messages) {
12621
12983
  const markers = [];
@@ -12674,9 +13036,26 @@ function formatCacheUsage(model, snapshot4, shape) {
12674
13036
  ...shape === void 0 ? {} : { requestMessages: shape.messages, requestMarkers: shape.markers }
12675
13037
  });
12676
13038
  }
13039
+ function stripThinkingBlocks(messages) {
13040
+ for (const message2 of messages) {
13041
+ if (message2.role !== "assistant" || !Array.isArray(message2.content)) continue;
13042
+ const blocks = message2.content;
13043
+ if (!blocks.some((block) => block?.type === "thinking")) continue;
13044
+ message2.content = blocks.filter((block) => block?.type !== "thinking");
13045
+ }
13046
+ }
13047
+ function isThinkingParamRejected(error) {
13048
+ const status = error?.status;
13049
+ if (status !== void 0 && status !== 400) return false;
13050
+ const message2 = error instanceof Error ? error.message : String(error ?? "");
13051
+ return /\bthinking\b/iu.test(message2) && /(budget_tokens|expected|not supported|unsupported|unknown|invalid|extra inputs|unrecognized)/iu.test(message2);
13052
+ }
12677
13053
  var AnthropicModelAdapter = class {
12678
13054
  client;
12679
13055
  maxOutputTokens;
13056
+ thinkingBudget;
13057
+ /** Set once an endpoint rejects the `thinking` parameter; later requests stop sending it. */
13058
+ #thinkingRejected = false;
12680
13059
  debugUsage;
12681
13060
  constructor(options) {
12682
13061
  const maxOutputTokens = options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
@@ -12684,6 +13063,7 @@ var AnthropicModelAdapter = class {
12684
13063
  throw new Error("maxOutputTokens must be a positive integer");
12685
13064
  }
12686
13065
  this.maxOutputTokens = maxOutputTokens;
13066
+ this.thinkingBudget = options.thinkingBudget ?? DEFAULT_THINKING_BUDGET;
12687
13067
  this.debugUsage = options.debugUsage ?? isEnvTruthy(process.env.FLAVOR_DEBUG_USAGE);
12688
13068
  this.client = options.client ?? new Anthropic({
12689
13069
  ...options.apiKey === void 0 ? {} : { apiKey: options.apiKey },
@@ -12691,6 +13071,16 @@ var AnthropicModelAdapter = class {
12691
13071
  ...options.headers === void 0 ? {} : { defaultHeaders: options.headers }
12692
13072
  });
12693
13073
  }
13074
+ /**
13075
+ * Extended-thinking request parameter when enabled, otherwise undefined.
13076
+ * Anthropic requires the budget to fit inside max_tokens with a 1024 floor.
13077
+ */
13078
+ #thinkingParam() {
13079
+ if (this.#thinkingRejected || this.thinkingBudget <= 0) return void 0;
13080
+ const budget = Math.min(this.thinkingBudget, this.maxOutputTokens - 1);
13081
+ if (budget < 1024) return void 0;
13082
+ return { type: "enabled", budget_tokens: budget };
13083
+ }
12694
13084
  #logUsage(request, snapshot4, shape) {
12695
13085
  const line = formatCacheUsage(request.model, snapshot4, shape);
12696
13086
  if (this.debugUsage) {
@@ -12746,7 +13136,13 @@ var AnthropicModelAdapter = class {
12746
13136
  }
12747
13137
  messages.push({ role: "user", content: results });
12748
13138
  } else if (message2.role === "assistant" && message2.toolCalls?.length) {
13139
+ const echoThinking = this.#thinkingRejected ? [] : (message2.thinkingBlocks ?? []).filter((block) => block.signature !== void 0);
12749
13140
  const content = [
13141
+ ...echoThinking.map((block) => ({
13142
+ type: "thinking",
13143
+ thinking: block.text,
13144
+ signature: block.signature
13145
+ })),
12750
13146
  ...modelContentText(message2.content) ? [{ type: "text", text: modelContentText(message2.content) }] : [],
12751
13147
  ...message2.toolCalls.map((call) => ({
12752
13148
  type: "tool_use",
@@ -12808,18 +13204,56 @@ var AnthropicModelAdapter = class {
12808
13204
  stream: true,
12809
13205
  messages,
12810
13206
  ...system ? { system } : {},
13207
+ ...(() => {
13208
+ const thinking = this.#thinkingParam();
13209
+ return thinking === void 0 ? {} : { thinking };
13210
+ })(),
12811
13211
  tools: [...request.tools].sort((a, b) => a.name.localeCompare(b.name)).map((tool) => ({
12812
13212
  name: tool.name,
12813
13213
  description: tool.description,
12814
13214
  input_schema: { ...tool.inputSchema, type: "object" }
12815
13215
  }))
12816
13216
  };
12817
- const stream = await this.client.messages.create(body, { signal: request.signal });
13217
+ let stream;
13218
+ try {
13219
+ stream = await this.client.messages.create(body, { signal: request.signal });
13220
+ } catch (error) {
13221
+ if (this.thinkingBudget > 0 && !this.#thinkingRejected && isThinkingParamRejected(error)) {
13222
+ this.#thinkingRejected = true;
13223
+ delete body.thinking;
13224
+ stripThinkingBlocks(body.messages);
13225
+ stream = await this.client.messages.create(body, { signal: request.signal });
13226
+ } else {
13227
+ throw error;
13228
+ }
13229
+ }
13230
+ const thinkingBuffers = /* @__PURE__ */ new Map();
12818
13231
  for await (const event of stream) {
12819
13232
  if (event.type === "message_start") {
12820
13233
  hasUsage = event.message?.usage !== void 0;
12821
13234
  inputTokens = updateInputUsage(inputUsage, event.message?.usage);
12822
13235
  outputTokens = event.message?.usage?.output_tokens ?? outputTokens;
13236
+ } else if (event.type === "content_block_start" && event.content_block?.type === "thinking" && event.index !== void 0) {
13237
+ thinkingBuffers.set(event.index, { text: "" });
13238
+ } else if (event.type === "content_block_delta" && event.delta?.type === "thinking_delta") {
13239
+ if (event.index !== void 0 && event.delta.thinking) {
13240
+ const pending = thinkingBuffers.get(event.index);
13241
+ if (pending) pending.text += event.delta.thinking;
13242
+ }
13243
+ if (event.delta.thinking) yield { type: "thinking", text: event.delta.thinking };
13244
+ } else if (event.type === "content_block_delta" && event.delta?.type === "signature_delta" && event.index !== void 0) {
13245
+ const pending = thinkingBuffers.get(event.index);
13246
+ if (pending) pending.signature = (pending.signature ?? "") + (event.delta.signature ?? "");
13247
+ } else if (event.type === "content_block_stop" && event.index !== void 0 && thinkingBuffers.has(event.index)) {
13248
+ const pending = thinkingBuffers.get(event.index);
13249
+ if (pending.text.length > 0 || pending.signature !== void 0) {
13250
+ yield {
13251
+ type: "thinking-block",
13252
+ text: pending.text,
13253
+ ...pending.signature === void 0 ? {} : { signature: pending.signature }
13254
+ };
13255
+ }
13256
+ thinkingBuffers.delete(event.index);
12823
13257
  } else if (event.type === "content_block_start" && event.content_block?.type === "tool_use" && event.index !== void 0 && event.content_block.id && event.content_block.name) {
12824
13258
  pendingTools.set(event.index, {
12825
13259
  id: event.content_block.id,
@@ -13022,12 +13456,14 @@ function formatOpenAIUsage(model, breakdown) {
13022
13456
  var OpenAIModelAdapter = class {
13023
13457
  client;
13024
13458
  debugUsage;
13459
+ thinkingEffort;
13025
13460
  constructor(options) {
13026
13461
  this.client = options.client ?? new OpenAI({
13027
13462
  ...options.apiKey === void 0 ? {} : { apiKey: options.apiKey },
13028
13463
  ...options.baseURL === void 0 ? {} : { baseURL: options.baseURL }
13029
13464
  });
13030
13465
  this.debugUsage = options.debugUsage ?? isEnvTruthy(process.env.FLAVOR_DEBUG_USAGE);
13466
+ this.thinkingEffort = options.thinkingEffort;
13031
13467
  }
13032
13468
  #logUsage(model, breakdown) {
13033
13469
  if (breakdown === void 0) return;
@@ -13049,6 +13485,7 @@ var OpenAIModelAdapter = class {
13049
13485
  const body = {
13050
13486
  model: request.model,
13051
13487
  input: (await Promise.all(request.messages.map(toInput))).flat(),
13488
+ ...this.thinkingEffort === void 0 ? {} : { reasoning: { effort: this.thinkingEffort } },
13052
13489
  tools: [...request.tools].sort((a, b) => a.name.localeCompare(b.name)).map((tool) => ({
13053
13490
  type: "function",
13054
13491
  name: tool.name,
@@ -13081,6 +13518,8 @@ var OpenAIModelAdapter = class {
13081
13518
  }
13082
13519
  } else if (event.type === "response.output_text.delta" && event.delta) {
13083
13520
  yield { type: "text", text: event.delta };
13521
+ } else if ((event.type === "response.reasoning_summary_text.delta" || event.type === "response.reasoning_text.delta") && event.delta) {
13522
+ yield { type: "thinking", text: event.delta };
13084
13523
  } else if (event.type === "response.function_call_arguments.done" && event.output_index !== void 0 && event.name) {
13085
13524
  const callId = callIds.get(event.output_index);
13086
13525
  if (callId && !emittedCalls.has(event.output_index)) {
@@ -17795,7 +18234,7 @@ function compileDefinition(record, scope2, workspace) {
17795
18234
  name: record.name,
17796
18235
  description: record.description,
17797
18236
  inputSchema,
17798
- modelInputSchema: record.inputSchema,
18237
+ modelInputSchema: strictJsonSchemaObject(record.inputSchema),
17799
18238
  modelStrict: true,
17800
18239
  ...record.agents === void 0 ? {} : { agents: record.agents },
17801
18240
  paths: () => [],
@@ -20859,6 +21298,7 @@ async function createProductionRuntime(options) {
20859
21298
  managedTools.push(tool);
20860
21299
  }
20861
21300
  if (harnessCreated) harness.replaceMainTools(tools);
21301
+ options.onToolsChange?.();
20862
21302
  };
20863
21303
  tools.push(...createManagedToolManagementTools({
20864
21304
  store: managedToolStore,
@@ -22188,6 +22628,25 @@ ${renderMemoryDocument(entries)}`;
22188
22628
  signal.throwIfAborted();
22189
22629
  return awaitWithSignal(Promise.resolve(handler(args, { workspace, signal })), signal);
22190
22630
  },
22631
+ managedToolCommands: () => managedTools.map(({ name, description }) => ({ name, description })).sort((left, right) => left.name.localeCompare(right.name)),
22632
+ runManagedTool: async (name, rawInput, signal) => {
22633
+ const tool = managedTools.find((candidate) => sameToolName(candidate.name, name));
22634
+ if (tool === void 0) throw new Error(`Registered tool "${name}" is no longer available.`);
22635
+ signal.throwIfAborted();
22636
+ const input = normalizeToolCallInput(rawInput);
22637
+ const call = { name: tool.name, input };
22638
+ const validation = harness.main.runtime.normalize(call);
22639
+ if (!validation.ok) throw new Error(`Invalid input for registered tool "${tool.name}": ${validation.error.message}`);
22640
+ harness.main.runtime.beginTurn();
22641
+ const result = await harness.main.runtime.execute(
22642
+ { name: tool.name, input: validation.input },
22643
+ { agent: "main", ownerId: "main", signal }
22644
+ );
22645
+ if (!result.ok) {
22646
+ throw new Error(`Registered tool "${tool.name}" failed (${result.error?.code ?? "unknown"}): ${result.error?.message ?? "Unknown error"}`);
22647
+ }
22648
+ return result.output !== void 0 ? result.output : result.content;
22649
+ },
22191
22650
  output: emitOutput,
22192
22651
  questions,
22193
22652
  async login() {
@@ -22238,8 +22697,12 @@ ${renderMemoryDocument(entries)}`;
22238
22697
  };
22239
22698
  registry.register(next.providerId, next.apiType === "anthropic" ? new AnthropicModelAdapter({
22240
22699
  ...adapterOptions,
22700
+ ...providerConfig?.thinkingBudget === void 0 ? {} : { thinkingBudget: providerConfig.thinkingBudget },
22241
22701
  ...providerConfig?.claudeClient === true ? { headers: CLAUDE_CLIENT_HEADERS } : {}
22242
- }) : new OpenAIModelAdapter(adapterOptions));
22702
+ }) : new OpenAIModelAdapter({
22703
+ ...adapterOptions,
22704
+ ...providerConfig?.thinkingEffort === void 0 ? {} : { thinkingEffort: providerConfig.thinkingEffort }
22705
+ }));
22243
22706
  effectiveLlm = next;
22244
22707
  mainModel = `${next.providerId}:${next.defaultModel}`;
22245
22708
  childModel = `${next.providerId}:${next.cheapModel}`;
@@ -22825,8 +23288,12 @@ async function registerConfiguredAdapters(providers, registry, environment, diag
22825
23288
  };
22826
23289
  const adapter = apiProtocol === "anthropic" ? new AnthropicModelAdapter({
22827
23290
  ...adapterOptions,
23291
+ ...runtimeProvider.thinkingBudget === void 0 ? {} : { thinkingBudget: runtimeProvider.thinkingBudget },
22828
23292
  ...runtimeProvider.claudeClient === true ? { headers: CLAUDE_CLIENT_HEADERS } : {}
22829
- }) : new OpenAIModelAdapter(adapterOptions);
23293
+ }) : new OpenAIModelAdapter({
23294
+ ...adapterOptions,
23295
+ ...runtimeProvider.thinkingEffort === void 0 ? {} : { thinkingEffort: runtimeProvider.thinkingEffort }
23296
+ });
22830
23297
  const cacheProfile = resolveCacheProfile({ apiType: apiProtocol, baseURL: runtimeProvider.baseURL });
22831
23298
  if (apiProtocol === "openai" && isDashScopeBaseURL(runtimeProvider.baseURL)) {
22832
23299
  diagnostics.push(
@@ -23191,6 +23658,8 @@ export {
23191
23658
  executeShell,
23192
23659
  packageVersion,
23193
23660
  SkillRegistry,
23661
+ charWidth,
23662
+ thinkingWindow,
23194
23663
  createTranscriptState,
23195
23664
  transcriptReducer,
23196
23665
  WorkspaceCheckpointStore,