@axlsdk/axl 0.25.0 → 0.25.1

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.
package/dist/index.cjs CHANGED
@@ -184,6 +184,7 @@ __export(index_exports, {
184
184
  TranscriptionProviderRegistry: () => TranscriptionProviderRegistry,
185
185
  UnsupportedEventSchemaVersionError: () => UnsupportedEventSchemaVersionError,
186
186
  UnsupportedModelInputError: () => UnsupportedModelInputError,
187
+ UnsupportedModelOptionError: () => UnsupportedModelOptionError,
187
188
  UnsupportedTranscriptionInputError: () => UnsupportedTranscriptionInputError,
188
189
  VLLM_PROFILE: () => VLLM_PROFILE,
189
190
  ValidationError: () => ValidationError,
@@ -272,6 +273,23 @@ var UnsupportedModelInputError = class extends AxlError {
272
273
  this.source = options.source;
273
274
  }
274
275
  };
276
+ var UnsupportedModelOptionError = class extends AxlError {
277
+ provider;
278
+ model;
279
+ option;
280
+ remediation;
281
+ constructor(options) {
282
+ super(
283
+ "UNSUPPORTED_MODEL_OPTION",
284
+ `Provider '${options.provider}' model '${options.model}' does not support ${options.option}. ${options.remediation}`
285
+ );
286
+ this.name = "UnsupportedModelOptionError";
287
+ this.provider = options.provider;
288
+ this.model = options.model;
289
+ this.option = options.option;
290
+ this.remediation = options.remediation;
291
+ }
292
+ };
275
293
  var InvalidTranscriptionInputError = class extends AxlError {
276
294
  constructor(message) {
277
295
  super("INVALID_TRANSCRIPTION_INPUT", message);
@@ -563,7 +581,7 @@ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null
563
581
  var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
564
582
  var thisCopy = {
565
583
  path: buildPath.startsWith("file:") ? (0, import_node_url.fileURLToPath)(buildPath) : buildPath,
566
- version: true ? "0.25.0" : "unknown"
584
+ version: true ? "0.25.1" : "unknown"
567
585
  };
568
586
  function warnCrossCopy(other, joined) {
569
587
  if (other === thisCopy) return;
@@ -3436,8 +3454,12 @@ var OpenAICompatibleProvider = class {
3436
3454
  for (const key of forbidden) {
3437
3455
  if (!userKeys.includes(key)) delete body[key];
3438
3456
  }
3457
+ this.validateFinalRequestBody(body);
3439
3458
  return body;
3440
3459
  }
3460
+ /** Native subclasses may reject model-invalid fields after providerOptions merge. */
3461
+ validateFinalRequestBody(_body) {
3462
+ }
3441
3463
  formatMessage(msg, model) {
3442
3464
  const modalities = this.inputModalities(model);
3443
3465
  const out = {
@@ -3845,6 +3867,24 @@ var withLongContext = (short) => ({
3845
3867
  output: short.output * 1.5
3846
3868
  });
3847
3869
  var DIRECT_OPENAI_CATALOG = [
3870
+ {
3871
+ aliases: ["gpt-6-astra"],
3872
+ short: { input: 10 / M, cachedInput: 1 / M, cacheWrite: 12.5 / M, output: 50 / M },
3873
+ long: { input: 20 / M, cachedInput: 2 / M, cacheWrite: 25 / M, output: 75 / M },
3874
+ contextBoundary: LONG_CONTEXT_BOUNDARY
3875
+ },
3876
+ {
3877
+ aliases: ["gpt-6-sol"],
3878
+ short: { input: 2 / M, cachedInput: 0.2 / M, cacheWrite: 2.5 / M, output: 10 / M },
3879
+ long: { input: 4 / M, cachedInput: 0.4 / M, cacheWrite: 5 / M, output: 15 / M },
3880
+ contextBoundary: LONG_CONTEXT_BOUNDARY
3881
+ },
3882
+ {
3883
+ aliases: ["gpt-6-luna"],
3884
+ short: { input: 0.1 / M, cachedInput: 0.01 / M, cacheWrite: 0.125 / M, output: 0.5 / M },
3885
+ long: { input: 0.2 / M, cachedInput: 0.02 / M, cacheWrite: 0.25 / M, output: 0.75 / M },
3886
+ contextBoundary: LONG_CONTEXT_BOUNDARY
3887
+ },
3848
3888
  {
3849
3889
  aliases: ["gpt-5.6", "gpt-5.6-sol"],
3850
3890
  snapshotBase: "gpt-5.6-sol",
@@ -4175,7 +4215,7 @@ function estimateDirectOpenAICost(model, usage, context) {
4175
4215
  const audioOutput = audio_output_tokens ?? 0;
4176
4216
  if (![prompt_tokens, completion_tokens, cached, cacheWrite, audioInput, audioOutput].every(
4177
4217
  (count) => Number.isSafeInteger(count) && count >= 0
4178
- ) || cached + cacheWrite + audioInput > prompt_tokens || audioOutput > completion_tokens) {
4218
+ ) || resolveOpenAIModelDescriptor(model).strictUsageTotals && (!Number.isSafeInteger(usage.total_tokens) || usage.total_tokens !== prompt_tokens + completion_tokens) || cached + cacheWrite + audioInput > prompt_tokens || audioOutput > completion_tokens) {
4179
4219
  return void 0;
4180
4220
  }
4181
4221
  if (audioInput > 0 && entry.audio === void 0 || audioOutput > 0 && entry.audio?.output === void 0) {
@@ -4200,57 +4240,206 @@ function estimateOpenAICost(model, promptTokens, completionTokens, cachedTokens)
4200
4240
  cached_tokens: cachedTokens
4201
4241
  });
4202
4242
  }
4203
- function isOSeriesModel(model) {
4204
- return /^(o1|o3|o4-mini)/.test(model);
4243
+ var EFFORT_FALLBACK = {
4244
+ none: "minimal",
4245
+ minimal: "low",
4246
+ low: "medium",
4247
+ medium: "high",
4248
+ max: "xhigh",
4249
+ xhigh: "high"
4250
+ };
4251
+ var BASE_EFFORTS = ["minimal", "low", "medium", "high"];
4252
+ function bothEndpoints(value) {
4253
+ return { chat: value, responses: value };
4205
4254
  }
4206
- function supportsReasoningEffort(model) {
4207
- return isOSeriesModel(model) || /^gpt-5/.test(model);
4255
+ function gpt6(id, efforts, chatTools) {
4256
+ return {
4257
+ id,
4258
+ family: "gpt-6",
4259
+ reasoning: true,
4260
+ efforts: bothEndpoints(efforts),
4261
+ defaultEffort: "medium",
4262
+ // Same policy as GPT-5.x: a portable `temperature` is dropped while
4263
+ // reasoning is active (including the active default). A raw
4264
+ // `providerOptions` sampling field is rejected by the final-body check.
4265
+ sampling: bothEndpoints("unless-effort-none"),
4266
+ chatTools,
4267
+ validatesFinalBody: true,
4268
+ strictUsageTotals: true
4269
+ };
4208
4270
  }
4209
- var GPT_56_REASONING_MODELS = /* @__PURE__ */ new Set([
4210
- "gpt-5.6",
4211
- "gpt-5.6-sol",
4212
- "gpt-5.6-terra",
4213
- "gpt-5.6-luna"
4214
- ]);
4215
- function supportsMaxReasoningEffort(model) {
4216
- return GPT_56_REASONING_MODELS.has(model);
4271
+ function gpt56(id) {
4272
+ const chat = ["none", ...BASE_EFFORTS, "xhigh"];
4273
+ return {
4274
+ id,
4275
+ family: "gpt-5.6",
4276
+ reasoning: true,
4277
+ efforts: { chat, responses: [...chat, "max"] },
4278
+ // Responses rejects temperature even at the provider-default effort.
4279
+ sampling: { chat: "when-effort-sent", responses: "always" },
4280
+ chatTools: "allowed",
4281
+ validatesFinalBody: false,
4282
+ strictUsageTotals: false
4283
+ };
4217
4284
  }
4218
- function supportsReasoningNone(model) {
4219
- return /^gpt-5\.[1-9]/.test(model);
4285
+ var OPENAI_EXACT_MODELS = new Map(
4286
+ [
4287
+ gpt6("gpt-6-astra", ["low", "medium", "high", "xhigh", "max"], "never"),
4288
+ gpt6("gpt-6-sol", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
4289
+ gpt6("gpt-6-luna", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
4290
+ gpt56("gpt-5.6"),
4291
+ gpt56("gpt-5.6-sol"),
4292
+ gpt56("gpt-5.6-terra"),
4293
+ gpt56("gpt-5.6-luna")
4294
+ ].map((descriptor) => [descriptor.id, descriptor])
4295
+ );
4296
+ var O_SERIES_DESCRIPTOR = {
4297
+ id: "o-series",
4298
+ family: "o-series",
4299
+ reasoning: true,
4300
+ efforts: bothEndpoints(BASE_EFFORTS),
4301
+ defaultEffort: "medium",
4302
+ sampling: bothEndpoints("always"),
4303
+ chatTools: "allowed",
4304
+ validatesFinalBody: false,
4305
+ strictUsageTotals: false
4306
+ };
4307
+ var GPT_5_PRO_DESCRIPTOR = {
4308
+ id: "gpt-5-pro",
4309
+ family: "gpt-5-pro",
4310
+ reasoning: true,
4311
+ efforts: bothEndpoints(["high"]),
4312
+ defaultEffort: "high",
4313
+ sampling: bothEndpoints("when-effort-sent"),
4314
+ chatTools: "allowed",
4315
+ validatesFinalBody: false,
4316
+ strictUsageTotals: false
4317
+ };
4318
+ var DEFAULT_DESCRIPTOR = {
4319
+ id: "default",
4320
+ family: "default",
4321
+ reasoning: false,
4322
+ // Never emitted (the model is not reasoning-capable); keeps the clamp total.
4323
+ efforts: bothEndpoints(BASE_EFFORTS),
4324
+ sampling: bothEndpoints("never"),
4325
+ chatTools: "allowed",
4326
+ validatesFinalBody: false,
4327
+ strictUsageTotals: false
4328
+ };
4329
+ function gpt5FamilyDescriptor(model) {
4330
+ const none = /^gpt-5\.[1-9]/.test(model);
4331
+ const xhigh = /^gpt-5\.([2-9]|\d{2,})/.test(model);
4332
+ const efforts = [
4333
+ ...none ? ["none"] : [],
4334
+ ...BASE_EFFORTS,
4335
+ ...xhigh ? ["xhigh"] : []
4336
+ ];
4337
+ return {
4338
+ id: "gpt-5",
4339
+ family: "gpt-5",
4340
+ reasoning: true,
4341
+ efforts: bothEndpoints(efforts),
4342
+ ...none ? {} : { defaultEffort: "medium" },
4343
+ sampling: bothEndpoints("when-effort-sent"),
4344
+ chatTools: "allowed",
4345
+ validatesFinalBody: false,
4346
+ strictUsageTotals: false
4347
+ };
4220
4348
  }
4221
- function supportsXhigh(model) {
4222
- return /^gpt-5\.([2-9]|\d{2,})/.test(model);
4349
+ var OPENAI_FAMILY_FALLBACKS = [
4350
+ { match: /^(o1|o3|o4-mini)/, describe: () => O_SERIES_DESCRIPTOR },
4351
+ { match: /^gpt-5-pro/, describe: () => GPT_5_PRO_DESCRIPTOR },
4352
+ { match: /^gpt-5/, describe: gpt5FamilyDescriptor }
4353
+ ];
4354
+ function resolveOpenAIModelDescriptor(model) {
4355
+ const exact = OPENAI_EXACT_MODELS.get(model);
4356
+ if (exact) return exact;
4357
+ const family = OPENAI_FAMILY_FALLBACKS.find((entry) => entry.match.test(model));
4358
+ return family ? family.describe(model) : DEFAULT_DESCRIPTOR;
4359
+ }
4360
+ function clampToDescriptor(descriptor, endpoint, effort) {
4361
+ const accepted = descriptor.efforts[endpoint];
4362
+ let candidate = effort;
4363
+ while (candidate !== void 0 && !accepted.includes(candidate)) {
4364
+ candidate = EFFORT_FALLBACK[candidate];
4365
+ }
4366
+ if (candidate === void 0) {
4367
+ throw new Error(
4368
+ `OpenAI descriptor '${descriptor.id}' accepts no ${endpoint} effort reachable from '${effort}'`
4369
+ );
4370
+ }
4371
+ return candidate;
4223
4372
  }
4224
- function clampReasoningEffort(model, effort) {
4225
- if (model.startsWith("gpt-5-pro")) return "high";
4226
- if (effort === "none" && !supportsReasoningNone(model)) return "minimal";
4227
- if (effort === "max" && !supportsMaxReasoningEffort(model)) {
4228
- return clampReasoningEffort(model, "xhigh");
4373
+ function stripsPortableSampling(descriptor, endpoint, wireEffort) {
4374
+ switch (descriptor.sampling[endpoint]) {
4375
+ case "never":
4376
+ return false;
4377
+ case "always":
4378
+ return true;
4379
+ case "when-effort-sent":
4380
+ return wireEffort !== void 0;
4381
+ case "unless-effort-none":
4382
+ return (wireEffort ?? descriptor.defaultEffort) !== "none";
4229
4383
  }
4230
- if (effort === "xhigh" && !supportsXhigh(model)) return "high";
4231
- return effort;
4232
4384
  }
4233
- function effortToReasoningEffort(effort, model) {
4234
- return effort === "max" && model !== void 0 && supportsMaxReasoningEffort(model) ? "max" : effort === "max" ? "xhigh" : effort;
4385
+ function isOSeriesModel(model) {
4386
+ return resolveOpenAIModelDescriptor(model).family === "o-series";
4235
4387
  }
4236
4388
  function budgetToReasoningEffort(budget) {
4237
4389
  if (budget <= 1024) return "low";
4238
4390
  if (budget <= 8192) return "medium";
4239
4391
  return "high";
4240
4392
  }
4393
+ function resolveEndpointReasoningEffort(model, endpoint, resolved) {
4394
+ const descriptor = resolveOpenAIModelDescriptor(model);
4395
+ if (!descriptor.reasoning) return void 0;
4396
+ const requested = resolved.hasBudgetOverride ? budgetToReasoningEffort(resolved.thinkingBudget) : !resolved.thinkingDisabled && resolved.activeEffort ? resolved.activeEffort : resolved.thinkingDisabled ? "none" : void 0;
4397
+ return requested === void 0 ? void 0 : clampToDescriptor(descriptor, endpoint, requested);
4398
+ }
4241
4399
  function resolveOpenAIReasoningEffort(model, resolved) {
4242
- if (!supportsReasoningEffort(model)) return void 0;
4243
- if (resolved.hasBudgetOverride) {
4244
- return clampReasoningEffort(model, budgetToReasoningEffort(resolved.thinkingBudget));
4245
- }
4246
- if (!resolved.thinkingDisabled && resolved.activeEffort) {
4247
- return clampReasoningEffort(model, effortToReasoningEffort(resolved.activeEffort, model));
4248
- }
4249
- return resolved.thinkingDisabled ? clampReasoningEffort(model, "none") : void 0;
4400
+ return resolveEndpointReasoningEffort(model, "responses", resolved);
4250
4401
  }
4251
4402
  function resolveOpenAIChatReasoningEffort(model, resolved) {
4252
- const effort = resolveOpenAIReasoningEffort(model, resolved);
4253
- return effort === "max" ? "xhigh" : effort;
4403
+ return resolveEndpointReasoningEffort(model, "chat", resolved);
4404
+ }
4405
+ function validateOpenAIFinalRequestBody(body, endpoint) {
4406
+ const model = body.model;
4407
+ if (typeof model !== "string") return;
4408
+ const descriptor = resolveOpenAIModelDescriptor(model);
4409
+ if (!descriptor.validatesFinalBody) return;
4410
+ const provider = endpoint === "chat" ? "openai" : "openai-responses";
4411
+ const fail = (option, remediation) => {
4412
+ throw new UnsupportedModelOptionError({ provider, model, option, remediation });
4413
+ };
4414
+ const rawEffort = endpoint === "chat" ? body.reasoning_effort : body.reasoning !== null && typeof body.reasoning === "object" ? body.reasoning.effort : void 0;
4415
+ const accepted = descriptor.efforts[endpoint];
4416
+ if (rawEffort !== void 0 && !accepted.includes(rawEffort)) {
4417
+ fail("reasoning effort", `Use one of: ${accepted.join(", ")}.`);
4418
+ }
4419
+ const activeReasoning = (rawEffort ?? descriptor.defaultEffort) !== "none";
4420
+ if (endpoint === "chat" && descriptor.chatTools !== "allowed") {
4421
+ const toolChoice = body.tool_choice;
4422
+ const toolIntent = Array.isArray(body.tools) && body.tools.length > 0 || toolChoice !== void 0 && toolChoice !== null && toolChoice !== "none" && toolChoice !== "auto";
4423
+ if (toolIntent && (descriptor.chatTools === "never" || activeReasoning)) {
4424
+ fail(
4425
+ "Chat Completions tool calling",
4426
+ descriptor.chatTools === "never" ? `Use openai-responses:${model} for tools.` : `Use openai-responses:${model} for reasoning with tools, or set effective reasoning_effort to 'none'.`
4427
+ );
4428
+ }
4429
+ }
4430
+ if (activeReasoning) {
4431
+ const forbidden = endpoint === "chat" ? ["temperature", "top_p", "top_logprobs", "logprobs"] : ["temperature", "top_p", "top_logprobs"];
4432
+ for (const key of forbidden) {
4433
+ if (body[key] !== void 0)
4434
+ fail(key, `Remove ${key} or set reasoning effort to 'none' on Sol or Luna.`);
4435
+ }
4436
+ if (endpoint === "responses" && Array.isArray(body.include) && body.include.includes("message.output_text.logprobs")) {
4437
+ fail(
4438
+ "message.output_text.logprobs",
4439
+ "Remove it from include or set reasoning effort to none on Sol or Luna."
4440
+ );
4441
+ }
4442
+ }
4254
4443
  }
4255
4444
  function resolveOpenAIEffortResolution(options, resolveWireEffort, endpoint) {
4256
4445
  const resolved = resolveThinkingOptions(options);
@@ -4266,11 +4455,15 @@ function resolveOpenAIEffortResolution(options, resolveWireEffort, endpoint) {
4266
4455
  };
4267
4456
  }
4268
4457
  var openaiReasoningEmit = (body, resolved, model) => {
4269
- const oSeries = isOSeriesModel(model);
4270
- const reasoningCapable = supportsReasoningEffort(model);
4271
4458
  const wireEffort = resolveOpenAIChatReasoningEffort(model, resolved);
4272
4459
  if (wireEffort) body.reasoning_effort = wireEffort;
4273
- return { stripTemperature: oSeries || reasoningCapable && wireEffort !== void 0 };
4460
+ return {
4461
+ stripTemperature: stripsPortableSampling(
4462
+ resolveOpenAIModelDescriptor(model),
4463
+ "chat",
4464
+ wireEffort
4465
+ )
4466
+ };
4274
4467
  };
4275
4468
  var OPENAI_PROFILE = {
4276
4469
  name: "openai",
@@ -4305,6 +4498,9 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
4305
4498
  "OpenAI Chat Completions"
4306
4499
  );
4307
4500
  }
4501
+ validateFinalRequestBody(body) {
4502
+ validateOpenAIFinalRequestBody(body, "chat");
4503
+ }
4308
4504
  computeCost(model, usage, _reportedCost, context) {
4309
4505
  return usage ? estimateDirectOpenAICost(model, usage, { ...context, baseUrl: this.baseUrl }) : void 0;
4310
4506
  }
@@ -4577,12 +4773,12 @@ var OpenAIResponsesProvider = class {
4577
4773
  // ---------------------------------------------------------------------------
4578
4774
  buildRequestBody(messages, options, stream) {
4579
4775
  const effectiveModel = typeof options.providerOptions?.model === "string" ? options.providerOptions.model : options.model;
4580
- const oSeries = isOSeriesModel(effectiveModel);
4581
- const reasoningCapable = supportsReasoningEffort(effectiveModel);
4776
+ const descriptor = resolveOpenAIModelDescriptor(effectiveModel);
4777
+ const reasoningCapable = descriptor.reasoning;
4582
4778
  const resolved = resolveThinkingOptions(options);
4583
4779
  const { includeThoughts } = resolved;
4584
4780
  const wireEffort = resolveOpenAIReasoningEffort(effectiveModel, resolved);
4585
- const stripTemp = oSeries || supportsMaxReasoningEffort(effectiveModel) || reasoningCapable && wireEffort !== void 0;
4781
+ const stripTemp = stripsPortableSampling(descriptor, "responses", wireEffort);
4586
4782
  const systemMessages = messages.filter((m) => m.role === "system");
4587
4783
  const nonSystemMessages = messages.filter((m) => m.role !== "system");
4588
4784
  const body = {
@@ -4631,6 +4827,7 @@ var OpenAIResponsesProvider = class {
4631
4827
  if (options.providerOptions) {
4632
4828
  Object.assign(body, options.providerOptions);
4633
4829
  }
4830
+ validateOpenAIFinalRequestBody(body, "responses");
4634
4831
  return body;
4635
4832
  }
4636
4833
  requestModel(body, fallback) {
@@ -4945,6 +5142,36 @@ function anthropicImageBlocks(parts, model) {
4945
5142
  }
4946
5143
  var ANTHROPIC_API_VERSION = "2023-06-01";
4947
5144
  var ANTHROPIC_FILES_BETA = "files-api-2025-04-14";
5145
+ var ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
5146
+ function isRecord(value) {
5147
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5148
+ }
5149
+ function hasReplayedThinking(body) {
5150
+ return Array.isArray(body.messages) && body.messages.some(
5151
+ (message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
5152
+ (block) => isRecord(block) && (block.type === "thinking" || block.type === "redacted_thinking")
5153
+ )
5154
+ );
5155
+ }
5156
+ function hasFinalFileImage(body) {
5157
+ return Array.isArray(body.messages) && body.messages.some(
5158
+ (message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
5159
+ (block) => isRecord(block) && block.type === "image" && isRecord(block.source) && block.source.type === "file"
5160
+ )
5161
+ );
5162
+ }
5163
+ function normalizeThinkingDrops(value) {
5164
+ if (!Array.isArray(value)) return void 0;
5165
+ const reasons = {};
5166
+ let droppedBlocks = 0;
5167
+ for (const entry of value) {
5168
+ if (!isRecord(entry) || entry.type !== "thinking_dropped") continue;
5169
+ const reason = entry.reason === "prefix_binding_mismatch" || entry.reason === "model_binding_mismatch" || entry.reason === "organization_binding_mismatch" || entry.reason === "end_user_binding_mismatch" ? entry.reason : "other";
5170
+ reasons[reason] = (reasons[reason] ?? 0) + 1;
5171
+ droppedBlocks++;
5172
+ }
5173
+ return droppedBlocks > 0 ? { droppedBlocks, reasons } : void 0;
5174
+ }
4948
5175
  function hasAnthropicProviderFileImage(messages) {
4949
5176
  return messages.some(
4950
5177
  (message) => Array.isArray(message.content) && message.content.some(
@@ -4953,11 +5180,19 @@ function hasAnthropicProviderFileImage(messages) {
4953
5180
  );
4954
5181
  }
4955
5182
  var CLAUDE_CAPABILITIES = {
5183
+ "claude-opus-5-5": {
5184
+ thinking: "adaptive-always-on",
5185
+ effortLevels: ["low", "medium", "high", "xhigh", "max"],
5186
+ manualBudget: false,
5187
+ stripTemperature: true,
5188
+ thinkingBinding: true
5189
+ },
4956
5190
  "claude-fable-5-1": {
4957
5191
  thinking: "adaptive-always-on",
4958
5192
  effortLevels: ["low", "medium", "high", "xhigh", "max"],
4959
5193
  manualBudget: false,
4960
- stripTemperature: true
5194
+ stripTemperature: true,
5195
+ thinkingBinding: true
4961
5196
  },
4962
5197
  "claude-fable-5": {
4963
5198
  thinking: "adaptive-always-on",
@@ -5051,6 +5286,7 @@ function resolveClaudeCapability(model) {
5051
5286
  }
5052
5287
  var DEFAULT_CACHE_READ_MULTIPLIER = 0.1;
5053
5288
  var ANTHROPIC_RATES = {
5289
+ "claude-opus-5-5": { input: 4e-6, output: 2e-5, cacheReadMultiplier: 0.05 },
5054
5290
  "claude-fable-5-1": { input: 1e-5, output: 5e-5, cacheReadMultiplier: 0.025 },
5055
5291
  "claude-fable-5": { input: 1e-5, output: 5e-5 },
5056
5292
  // Limited availability (Glasswing). Priced from the public pricing table; no
@@ -5485,11 +5721,12 @@ var AnthropicProvider = class {
5485
5721
  // chat - non-streaming completion
5486
5722
  // ---------------------------------------------------------------------------
5487
5723
  async chat(messages, options) {
5724
+ const body = this.buildRequestBody(messages, options, false);
5488
5725
  const headers = this.buildHeaders(
5489
5726
  await this.resolveKey(),
5490
- hasAnthropicProviderFileImage(messages)
5727
+ hasAnthropicProviderFileImage(messages) || hasFinalFileImage(body),
5728
+ this.requiresBindingBeta(body)
5491
5729
  );
5492
- const body = this.buildRequestBody(messages, options, false);
5493
5730
  const pricingContext = pricingContextFromBody(body);
5494
5731
  const recorder = new CallTimingRecorder(options.requestLifecycle);
5495
5732
  const governor = this.governorFor(pricingContext.model ?? options.model);
@@ -5527,11 +5764,12 @@ var AnthropicProvider = class {
5527
5764
  // stream - SSE streaming completion
5528
5765
  // ---------------------------------------------------------------------------
5529
5766
  async *stream(messages, options) {
5767
+ const body = this.buildRequestBody(messages, options, true);
5530
5768
  const headers = this.buildHeaders(
5531
5769
  await this.resolveKey(),
5532
- hasAnthropicProviderFileImage(messages)
5770
+ hasAnthropicProviderFileImage(messages) || hasFinalFileImage(body),
5771
+ this.requiresBindingBeta(body)
5533
5772
  );
5534
- const body = this.buildRequestBody(messages, options, true);
5535
5773
  const pricingContext = pricingContextFromBody(body);
5536
5774
  const recorder = new CallTimingRecorder(options.requestLifecycle);
5537
5775
  const governor = this.governorFor(pricingContext.model ?? options.model);
@@ -5573,12 +5811,61 @@ var AnthropicProvider = class {
5573
5811
  // ---------------------------------------------------------------------------
5574
5812
  // Internal: request building
5575
5813
  // ---------------------------------------------------------------------------
5576
- buildHeaders(apiKey, requiresFilesBeta = false) {
5814
+ buildHeaders(apiKey, requiresFilesBeta = false, requiresBindingBeta = false) {
5815
+ const betas = [
5816
+ ...requiresFilesBeta ? [ANTHROPIC_FILES_BETA] : [],
5817
+ ...requiresBindingBeta ? [ANTHROPIC_THINKING_BINDING_BETA] : []
5818
+ ];
5577
5819
  return {
5578
5820
  "Content-Type": "application/json",
5579
5821
  "x-api-key": apiKey,
5580
5822
  "anthropic-version": ANTHROPIC_API_VERSION,
5581
- ...requiresFilesBeta ? { "anthropic-beta": ANTHROPIC_FILES_BETA } : {}
5823
+ ...betas.length > 0 ? { "anthropic-beta": betas.join(",") } : {}
5824
+ };
5825
+ }
5826
+ requiresBindingBeta(body) {
5827
+ const thinking = body.thinking;
5828
+ return resolveClaudeCapability(String(body.model))?.thinkingBinding === true && (hasReplayedThinking(body) || isRecord(thinking) && thinking.block_binding !== void 0);
5829
+ }
5830
+ validateAndBindFinalBody(body) {
5831
+ const model = typeof body.model === "string" ? body.model : "";
5832
+ if (resolveClaudeCapability(model)?.thinkingBinding !== true) return;
5833
+ const reject = (option, remediation) => {
5834
+ throw new UnsupportedModelOptionError({ provider: this.name, model, option, remediation });
5835
+ };
5836
+ const toolChoice = body.tool_choice;
5837
+ if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
5838
+ reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
5839
+ }
5840
+ if (body.thinking !== void 0 && (!isRecord(body.thinking) || body.thinking.type !== "adaptive" || body.thinking.budget_tokens !== void 0)) {
5841
+ reject(
5842
+ "manual or disabled thinking",
5843
+ "Use thinking: { type: 'adaptive' } and output_config.effort."
5844
+ );
5845
+ }
5846
+ const outputConfig = body.output_config;
5847
+ if (outputConfig !== void 0 && (!isRecord(outputConfig) || outputConfig.effort !== void 0 && !["low", "medium", "high", "xhigh", "max"].includes(String(outputConfig.effort)))) {
5848
+ reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
5849
+ }
5850
+ if (body.temperature !== void 0 && body.temperature !== 1) {
5851
+ reject("temperature", "Omit temperature or use the default value 1.");
5852
+ }
5853
+ if (body.top_p !== void 0 && (typeof body.top_p !== "number" || body.top_p < 0.99 || body.top_p > 1)) {
5854
+ reject("top_p", "Omit top_p or use a value from 0.99 to 1.");
5855
+ }
5856
+ if (body.top_k !== void 0) {
5857
+ reject("top_k", "Omit top_k on this model.");
5858
+ }
5859
+ const replayed = hasReplayedThinking(body);
5860
+ if (!replayed) return;
5861
+ const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
5862
+ const binding = thinking.block_binding;
5863
+ if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
5864
+ reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
5865
+ }
5866
+ body.thinking = {
5867
+ ...thinking,
5868
+ block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
5582
5869
  };
5583
5870
  }
5584
5871
  /** Extract a human-readable message from an API error response body. */
@@ -5657,6 +5944,7 @@ ${jsonInstruction}` : jsonInstruction;
5657
5944
  if (options.providerOptions) {
5658
5945
  Object.assign(body, options.providerOptions);
5659
5946
  }
5947
+ this.validateAndBindFinalBody(body);
5660
5948
  return body;
5661
5949
  }
5662
5950
  /**
@@ -5813,6 +6101,7 @@ ${jsonInstruction}` : jsonInstruction;
5813
6101
  }
5814
6102
  }
5815
6103
  const normalized = json.usage ? normalizeAnthropicUsage(json.usage) : void 0;
6104
+ const reasoningContextReset = normalizeThinkingDrops(json.input_transformations);
5816
6105
  const effectiveModel = typeof json.model === "string" ? json.model : pricingContext.model;
5817
6106
  if (hasFallbackBoundary) {
5818
6107
  throw new Error(
@@ -5827,7 +6116,8 @@ ${jsonInstruction}` : jsonInstruction;
5827
6116
  usage: normalized?.usage,
5828
6117
  cost,
5829
6118
  costProvenance: tableEstimate(cost),
5830
- providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary ? { anthropicThinkingBlocks: thinkingBlocks } : void 0
6119
+ providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary ? { anthropicThinkingBlocks: thinkingBlocks } : void 0,
6120
+ ...reasoningContextReset ? { diagnostics: { reasoningContextReset } } : {}
5831
6121
  };
5832
6122
  }
5833
6123
  // ---------------------------------------------------------------------------
@@ -5849,6 +6139,7 @@ ${jsonInstruction}` : jsonInstruction;
5849
6139
  let hasFallbackBoundary = false;
5850
6140
  let hasFallbackIterationSignal = false;
5851
6141
  let refused = false;
6142
+ let reasoningContextReset;
5852
6143
  const finalizeUsage = () => {
5853
6144
  const normalized = rawUsage ? normalizeAnthropicUsage(rawUsage) : void 0;
5854
6145
  usage = normalized?.usage;
@@ -5861,7 +6152,8 @@ ${jsonInstruction}` : jsonInstruction;
5861
6152
  usage,
5862
6153
  cost,
5863
6154
  costProvenance: tableEstimate(cost),
5864
- providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary && !hasFallbackIterationSignal ? { anthropicThinkingBlocks: thinkingBlocks } : void 0
6155
+ providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary && !hasFallbackIterationSignal ? { anthropicThinkingBlocks: thinkingBlocks } : void 0,
6156
+ ...reasoningContextReset ? { diagnostics: { reasoningContextReset } } : {}
5865
6157
  };
5866
6158
  };
5867
6159
  try {
@@ -5954,6 +6246,7 @@ ${jsonInstruction}` : jsonInstruction;
5954
6246
  rawUsage = mergeAnthropicUsage(rawUsage, event.message.usage);
5955
6247
  }
5956
6248
  if (typeof event.message?.model === "string") effectiveModel = event.message.model;
6249
+ reasoningContextReset = normalizeThinkingDrops(event.message?.input_transformations);
5957
6250
  const messageFallback = hasFallbackIteration(event.message?.usage?.iterations);
5958
6251
  if (isAnthropicResponseModifier(
5959
6252
  "inference_geo",
@@ -5970,6 +6263,10 @@ ${jsonInstruction}` : jsonInstruction;
5970
6263
  break;
5971
6264
  }
5972
6265
  case "message_delta": {
6266
+ const finalTransformations = event.input_transformations ?? event.delta?.input_transformations;
6267
+ if (finalTransformations !== void 0) {
6268
+ reasoningContextReset = normalizeThinkingDrops(finalTransformations);
6269
+ }
5973
6270
  if (event.usage) {
5974
6271
  rawUsage = mergeAnthropicUsage(rawUsage, event.usage);
5975
6272
  finalizeUsage();
@@ -6198,7 +6495,31 @@ var GEMINI_PRICING = {
6198
6495
  },
6199
6496
  "gemini-3.8-flash": { input: 75e-8, cached: 75e-9, output: 375e-8 }
6200
6497
  };
6498
+ var GEMINI_FLASH_SUCCESSOR_PRICING = {
6499
+ ...GEMINI_PRICING,
6500
+ "gemini-3.6-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 },
6501
+ "gemini-3.7-flash": {
6502
+ input: 15e-7,
6503
+ cached: 15e-8,
6504
+ output: 75e-7,
6505
+ audioInput: 15e-7
6506
+ },
6507
+ "gemini-3.8-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 }
6508
+ };
6509
+ var GEMINI_FLASH_SUCCESSOR_START_MS = Date.UTC(2027, 0, 1);
6510
+ function geminiRatesAtDispatch(at) {
6511
+ return at < GEMINI_FLASH_SUCCESSOR_START_MS ? GEMINI_PRICING : GEMINI_FLASH_SUCCESSOR_PRICING;
6512
+ }
6201
6513
  var CANONICAL_GEMINI_BASE_URL = GEMINI_DEFAULT_BASE_URL;
6514
+ function geminiPricingTimingObserver(context, recorder) {
6515
+ return {
6516
+ ...recorder.observer,
6517
+ onDispatch: (attempt, at) => {
6518
+ context.rates = geminiRatesAtDispatch(at);
6519
+ recorder.observer.onDispatch?.(attempt, at);
6520
+ }
6521
+ };
6522
+ }
6202
6523
  function isValidTokenCount2(value) {
6203
6524
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
6204
6525
  }
@@ -6279,8 +6600,8 @@ function geminiInteractionErrorStatus(code) {
6279
6600
  function isEligibleGeminiPricing(context, hasDefinitiveStandardResponseTier, hasInvalidResponseTier) {
6280
6601
  return context.eligibleRequest && isStandardGeminiRequestTier(context.serviceTier) && hasDefinitiveStandardResponseTier && !hasInvalidResponseTier;
6281
6602
  }
6282
- function estimateGeminiCost(model, usage) {
6283
- const pricing = GEMINI_PRICING[model];
6603
+ function estimateGeminiCost(model, usage, rates) {
6604
+ const pricing = rates && Object.hasOwn(rates, model) ? rates[model] : void 0;
6284
6605
  const cached = usage.cachedTokens ?? 0;
6285
6606
  if (!pricing || !isValidTokenCount2(usage.inputTokens) || !isValidTokenCount2(usage.outputTokens) || !isValidTokenCount2(cached) || cached > usage.inputTokens) {
6286
6607
  return void 0;
@@ -6608,7 +6929,7 @@ var GeminiProvider = class {
6608
6929
  {
6609
6930
  governor: this.governorFor(pricingContext.model),
6610
6931
  provider: this.name,
6611
- timing: recorder.observer,
6932
+ timing: geminiPricingTimingObserver(pricingContext, recorder),
6612
6933
  admission: options.dispatchAdmission
6613
6934
  }
6614
6935
  );
@@ -6651,7 +6972,7 @@ var GeminiProvider = class {
6651
6972
  {
6652
6973
  governor: this.governorFor(pricingContext.model),
6653
6974
  provider: this.name,
6654
- timing: recorder.observer,
6975
+ timing: geminiPricingTimingObserver(pricingContext, recorder),
6655
6976
  admission: options.dispatchAdmission
6656
6977
  }
6657
6978
  );
@@ -6689,7 +7010,7 @@ var GeminiProvider = class {
6689
7010
  {
6690
7011
  governor: this.governorFor(pricingContext.model),
6691
7012
  provider: this.name,
6692
- timing: recorder.observer,
7013
+ timing: geminiPricingTimingObserver(pricingContext, recorder),
6693
7014
  admission: options.dispatchAdmission
6694
7015
  }
6695
7016
  );
@@ -6725,7 +7046,7 @@ var GeminiProvider = class {
6725
7046
  {
6726
7047
  governor: this.governorFor(pricingContext.model),
6727
7048
  provider: this.name,
6728
- timing: recorder.observer,
7049
+ timing: geminiPricingTimingObserver(pricingContext, recorder),
6729
7050
  admission: options.dispatchAdmission
6730
7051
  }
6731
7052
  );
@@ -6944,7 +7265,7 @@ var GeminiProvider = class {
6944
7265
  )) {
6945
7266
  return void 0;
6946
7267
  }
6947
- return estimateGeminiCost(effectiveModel, normalized.pricingUsage);
7268
+ return estimateGeminiCost(effectiveModel, normalized.pricingUsage, pricingContext.rates);
6948
7269
  }
6949
7270
  /**
6950
7271
  * Whether every model-produced step is text. A non-text reply part (image,
@@ -7529,7 +7850,7 @@ var GeminiProvider = class {
7529
7850
  pricingContext,
7530
7851
  isDefinitiveStandardGeminiResponseTier(json.usageMetadata?.serviceTier),
7531
7852
  json.usageMetadata?.serviceTier !== void 0 && !isDefinitiveStandardGeminiResponseTier(json.usageMetadata.serviceTier)
7532
- ) ? estimateGeminiCost(effectiveModel, normalized.pricingUsage) : void 0;
7853
+ ) ? estimateGeminiCost(effectiveModel, normalized.pricingUsage, pricingContext.rates) : void 0;
7533
7854
  const rawParts = candidate?.content?.parts;
7534
7855
  const providerMetadata = rawParts ? { geminiParts: rawParts } : void 0;
7535
7856
  return {
@@ -7620,7 +7941,7 @@ var GeminiProvider = class {
7620
7941
  pricingContext,
7621
7942
  hasDefinitiveStandardResponseTier,
7622
7943
  hasInvalidResponseTier
7623
- ) ? estimateGeminiCost(effectiveModel, normalizedUsage.pricingUsage) : void 0;
7944
+ ) ? estimateGeminiCost(effectiveModel, normalizedUsage.pricingUsage, pricingContext.rates) : void 0;
7624
7945
  yield {
7625
7946
  type: "done",
7626
7947
  usage: normalizedUsage?.usage,
@@ -9270,7 +9591,7 @@ var TranscriptionProviderRegistry = class {
9270
9591
 
9271
9592
  // src/context.ts
9272
9593
  var import_node_async_hooks3 = require("async_hooks");
9273
- var import_node_crypto = require("crypto");
9594
+ var import_node_crypto2 = require("crypto");
9274
9595
  var import_zod2 = require("zod");
9275
9596
 
9276
9597
  // src/input.ts
@@ -9533,6 +9854,95 @@ function sessionHistoryForAsk(history, normalizedInput) {
9533
9854
  return snapshot;
9534
9855
  }
9535
9856
 
9857
+ // src/compaction.ts
9858
+ var import_node_crypto = require("crypto");
9859
+ var SUMMARY_SYSTEM_PROMPT = "Summarize the following conversation concisely, preserving key facts, decisions, and context needed for continuing the conversation.";
9860
+ var SUMMARY_MAX_TOKENS = 1024;
9861
+ function buildSummaryPrompt(messages, previousSummary) {
9862
+ return [
9863
+ ...previousSummary ? [`Previous conversation summary: ${previousSummary}`] : [],
9864
+ ...messages.map((m) => `${m.role}: ${summarizeModelInput(m.content)}`)
9865
+ ].join("\n");
9866
+ }
9867
+ function requestSummary(provider, options) {
9868
+ return provider.chat(
9869
+ [
9870
+ { role: "system", content: SUMMARY_SYSTEM_PROMPT },
9871
+ { role: "user", content: options.prompt }
9872
+ ],
9873
+ {
9874
+ model: options.model,
9875
+ maxTokens: SUMMARY_MAX_TOKENS,
9876
+ ...options.signal ? { signal: options.signal } : {}
9877
+ }
9878
+ );
9879
+ }
9880
+ function summaryContextMessage(summary) {
9881
+ return {
9882
+ role: "system",
9883
+ origin: "runtime",
9884
+ content: `Summary of earlier conversation:
9885
+ ${summary}`
9886
+ };
9887
+ }
9888
+ function withoutAnthropicThinking(message) {
9889
+ const metadata = message.providerMetadata;
9890
+ if (!metadata || !Object.hasOwn(metadata, "anthropicThinkingBlocks")) return message;
9891
+ const retainedMetadata = { ...metadata };
9892
+ delete retainedMetadata.anthropicThinkingBlocks;
9893
+ return {
9894
+ ...message,
9895
+ ...Object.keys(retainedMetadata).length > 0 ? { providerMetadata: retainedMetadata } : { providerMetadata: void 0 }
9896
+ };
9897
+ }
9898
+ function anthropicThinkingBlockCount(message) {
9899
+ const blocks = message.providerMetadata?.anthropicThinkingBlocks;
9900
+ if (!Array.isArray(blocks)) return 0;
9901
+ return blocks.filter(
9902
+ (block) => block !== null && typeof block === "object" && (block.type === "thinking" || block.type === "redacted_thinking")
9903
+ ).length;
9904
+ }
9905
+ function askSummaryMetaKey(agentName) {
9906
+ return `askSummary:${agentName}`;
9907
+ }
9908
+ function isCount(value) {
9909
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
9910
+ }
9911
+ function parseAskSummaryRecord(value) {
9912
+ if (!value || typeof value !== "object") return void 0;
9913
+ const record = value;
9914
+ if (typeof record.summary !== "string" || !isCount(record.coveredCount) || typeof record.prefixHash !== "string" || typeof record.summaryModelUri !== "string" || !isCount(record.invalidatedThinkingThrough) || record.sourceSummary !== void 0 && typeof record.sourceSummary !== "string") {
9915
+ return void 0;
9916
+ }
9917
+ return {
9918
+ summary: record.summary,
9919
+ coveredCount: record.coveredCount,
9920
+ prefixHash: record.prefixHash,
9921
+ ...record.sourceSummary !== void 0 ? { sourceSummary: record.sourceSummary } : {},
9922
+ summaryModelUri: record.summaryModelUri,
9923
+ invalidatedThinkingThrough: record.invalidatedThinkingThrough
9924
+ };
9925
+ }
9926
+ function isPlainObject(value) {
9927
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
9928
+ const proto = Object.getPrototypeOf(value);
9929
+ return proto === Object.prototype || proto === null;
9930
+ }
9931
+ function summaryPrefixHash(history, coveredCount) {
9932
+ let canonical;
9933
+ try {
9934
+ canonical = JSON.stringify(
9935
+ history.slice(0, coveredCount),
9936
+ (_key, value) => isPlainObject(value) ? Object.fromEntries(
9937
+ Object.keys(value).sort().map((key) => [key, value[key]])
9938
+ ) : value
9939
+ );
9940
+ } catch {
9941
+ return void 0;
9942
+ }
9943
+ return (0, import_node_crypto.createHash)("sha256").update(canonical).digest("hex");
9944
+ }
9945
+
9536
9946
  // src/partial-json.ts
9537
9947
  var MAX_DEPTH = 256;
9538
9948
  function parsePartialJson(input) {
@@ -11169,9 +11579,9 @@ var LEGACY_REDACTION_RULES = {
11169
11579
  // which is user content or PII (field paths are schema-shape, preserved like
11170
11580
  // `string_delta.path`). Passthrough, as an explicit reviewed decision.
11171
11581
  schema_diagnostic: passthrough,
11172
- // `provider_diagnostic` carries only provider capability metadata — a provider
11173
- // name, a model id, and two effort level strings. No application data or user
11174
- // content ever reaches it. Passthrough, as an explicit reviewed decision.
11582
+ // `provider_diagnostic` carries only provider/model metadata, effort levels,
11583
+ // and bounded dropped-thinking reason counts. Raw transformation paths and
11584
+ // signed thinking never enter this event. Passthrough is reviewed here.
11175
11585
  provider_diagnostic: passthrough,
11176
11586
  log: (e) => {
11177
11587
  if (!e.data || typeof e.data !== "object" || Array.isArray(e.data)) return e;
@@ -13176,7 +13586,14 @@ var WorkflowContext = class _WorkflowContext {
13176
13586
  * suppresses late branch events after bounded finalization. */
13177
13587
  workflowLifecycleState;
13178
13588
  signal;
13179
- summaryCache;
13589
+ /** Durable summary of messages removed by Session.history.maxMessages. */
13590
+ sessionSummary;
13591
+ /** Per-agent `maxContext` summaries, keyed by agent name. `null` records a
13592
+ * store lookup that found nothing. Mirrored to session metadata
13593
+ * (`askSummary:<agent>`) when this execution belongs to a session, so a
13594
+ * later execution can reuse the same exact-prefix boundary. Never the
13595
+ * durable `sessionSummary`. */
13596
+ askSummaries = /* @__PURE__ */ new Map();
13180
13597
  /** Consecutive provider calls with promptCache on that wrote to the cache
13181
13598
  * without reading from it (prefix changes per call), and consecutive calls
13182
13599
  * with no cache activity at all (prefix below the model's minimum, which
@@ -13352,7 +13769,7 @@ var WorkflowContext = class _WorkflowContext {
13352
13769
  endEmitted: false
13353
13770
  };
13354
13771
  if (init.metadata?.summaryCache) {
13355
- this.summaryCache = init.metadata.summaryCache;
13772
+ this.sessionSummary = init.metadata.summaryCache;
13356
13773
  }
13357
13774
  }
13358
13775
  /**
@@ -13680,7 +14097,7 @@ var WorkflowContext = class _WorkflowContext {
13680
14097
  this._autoCheckpointName("ask", agentName),
13681
14098
  async () => {
13682
14099
  const parentFrame = askStorage.getStore();
13683
- const askId = (0, import_node_crypto.randomUUID)();
14100
+ const askId = (0, import_node_crypto2.randomUUID)();
13684
14101
  const depth = (parentFrame?.depth ?? -1) + 1;
13685
14102
  const stepRef = parentFrame?.stepRef ?? this.stepRefRoot;
13686
14103
  const frame = {
@@ -13977,6 +14394,7 @@ var WorkflowContext = class _WorkflowContext {
13977
14394
  if (systemPrompt) {
13978
14395
  messages.push({ role: "system", content: systemPrompt });
13979
14396
  }
14397
+ const cachedSummaryMessage = this.sessionSummary ? summaryContextMessage(this.sessionSummary) : void 0;
13980
14398
  const maxContext = agent2._config.maxContext;
13981
14399
  if (maxContext && sessionHistory.length > 0) {
13982
14400
  const reserveTokens = this.config.contextManagement?.reserveTokens ?? 2e3;
@@ -14001,22 +14419,44 @@ var WorkflowContext = class _WorkflowContext {
14001
14419
  }
14002
14420
  });
14003
14421
  }
14004
- if (historyEstimate.tokens > availableForHistory) {
14005
- const summarizedMessages = await this.summarizeHistory(
14422
+ const summaryTokens = cachedSummaryMessage ? estimateMessagesTokens([cachedSummaryMessage]).tokens : 0;
14423
+ if (historyEstimate.tokens + summaryTokens > availableForHistory) {
14424
+ const projection = await this.summarizeHistory(
14425
+ agent2._name,
14426
+ modelUri,
14006
14427
  provider,
14007
14428
  model,
14008
14429
  sessionHistory,
14009
14430
  availableForHistory
14010
14431
  );
14011
- for (const msg of summarizedMessages) {
14432
+ if (this.budgetContext?.exceeded && this.budgetContext.policy !== "warn") {
14433
+ const { limit, totalCost: spent, policy } = this.budgetContext;
14434
+ throw new BudgetExceededError(limit, spent, policy);
14435
+ }
14436
+ if (projection.removedThinkingBlocks > 0) {
14437
+ this.emitEvent({
14438
+ type: "provider_diagnostic",
14439
+ agent: agent2._name,
14440
+ data: {
14441
+ kind: "reasoning_context_reset",
14442
+ ...provider.name ? { provider: provider.name } : {},
14443
+ model: typeof providerOptions?.model === "string" ? providerOptions.model : model,
14444
+ droppedBlocks: projection.removedThinkingBlocks,
14445
+ reasons: { client_prefix_rewrite: projection.removedThinkingBlocks }
14446
+ }
14447
+ });
14448
+ }
14449
+ for (const msg of projection.messages) {
14012
14450
  messages.push(msg);
14013
14451
  }
14014
14452
  } else {
14453
+ if (cachedSummaryMessage) messages.push(cachedSummaryMessage);
14015
14454
  for (const msg of sessionHistory) {
14016
14455
  messages.push(msg);
14017
14456
  }
14018
14457
  }
14019
14458
  } else {
14459
+ if (cachedSummaryMessage) messages.push(cachedSummaryMessage);
14020
14460
  for (const msg of sessionHistory) {
14021
14461
  messages.push(msg);
14022
14462
  }
@@ -14117,6 +14557,7 @@ ${appendedSchemaText}`;
14117
14557
  }
14118
14558
  const startTime = Date.now();
14119
14559
  const askClock = currentAskClock();
14560
+ const pausedAtStartMs = askClock ? pausedAskClockMs(askClock, startTime) : 0;
14120
14561
  const timingTotals = { turns: 0, queuedMs: 0, retryMs: 0, wireMs: 0 };
14121
14562
  const currentMessages = [...messages];
14122
14563
  let turns = 0;
@@ -14134,7 +14575,7 @@ ${appendedSchemaText}`;
14134
14575
  this.currentSignal?.throwIfAborted();
14135
14576
  const now = Date.now();
14136
14577
  const elapsedMs = now - startTime;
14137
- const pausedMs = askClock ? pausedAskClockMs(askClock, now) : 0;
14578
+ const pausedMs = askClock ? Math.max(0, pausedAskClockMs(askClock, now) - pausedAtStartMs) : 0;
14138
14579
  const chargedMs = Math.max(0, elapsedMs - Math.min(pausedMs, Math.max(0, elapsedMs)));
14139
14580
  if (chargedMs > timeoutMs) {
14140
14581
  throw new TimeoutError(
@@ -14389,6 +14830,7 @@ ${appendedSchemaText}`;
14389
14830
  usage: chunk.usage,
14390
14831
  cost: chunk.cost,
14391
14832
  providerMetadata: chunk.providerMetadata,
14833
+ diagnostics: chunk.diagnostics,
14392
14834
  timing: chunk.timing
14393
14835
  };
14394
14836
  }
@@ -14506,6 +14948,34 @@ ${appendedSchemaText}`;
14506
14948
  timingTotals.retryMs += response.timing.retryMs;
14507
14949
  timingTotals.wireMs += response.timing.wireMs;
14508
14950
  }
14951
+ const reasoningReset = response.diagnostics?.reasoningContextReset;
14952
+ if (reasoningReset && Number.isSafeInteger(reasoningReset.droppedBlocks) && reasoningReset.droppedBlocks > 0) {
14953
+ const reasons = {};
14954
+ for (const reason of [
14955
+ "prefix_binding_mismatch",
14956
+ "model_binding_mismatch",
14957
+ "organization_binding_mismatch",
14958
+ "end_user_binding_mismatch",
14959
+ "client_prefix_rewrite",
14960
+ "other"
14961
+ ]) {
14962
+ const count = reasoningReset.reasons?.[reason];
14963
+ if (typeof count === "number" && Number.isSafeInteger(count) && count > 0) {
14964
+ reasons[reason] = count;
14965
+ }
14966
+ }
14967
+ this.emitEvent({
14968
+ type: "provider_diagnostic",
14969
+ agent: agent2._name,
14970
+ data: {
14971
+ kind: "reasoning_context_reset",
14972
+ ...provider.name ? { provider: provider.name } : {},
14973
+ model: typeof providerOptions?.model === "string" ? providerOptions.model : model,
14974
+ droppedBlocks: reasoningReset.droppedBlocks,
14975
+ reasons
14976
+ }
14977
+ });
14978
+ }
14509
14979
  this.emitEvent({
14510
14980
  type: "agent_call_end",
14511
14981
  agent: agent2._name,
@@ -14556,7 +15026,7 @@ ${appendedSchemaText}`;
14556
15026
  const sourceFrame = askStorage.getStore();
14557
15027
  const handoffFromAskId = sourceFrame?.askId ?? this.executionId;
14558
15028
  const handoffSourceDepth = sourceFrame?.depth ?? 0;
14559
- const handoffToAskId = (0, import_node_crypto.randomUUID)();
15029
+ const handoffToAskId = (0, import_node_crypto2.randomUUID)();
14560
15030
  const handoffTargetDepth = handoffSourceDepth + 1;
14561
15031
  const targetFrame = {
14562
15032
  askId: handoffToAskId,
@@ -15248,31 +15718,65 @@ ${appendedSchemaText}`;
15248
15718
  }
15249
15719
  return defs;
15250
15720
  }
15721
+ /** Session id for session-scoped ask-summary persistence, when this
15722
+ * execution belongs to a session and has a store to persist into. */
15723
+ askSummarySessionId() {
15724
+ const sessionId = this.metadata?.sessionId;
15725
+ if (this.metadata?.sessionPersist === false) return void 0;
15726
+ return this.stateStore && typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
15727
+ }
15728
+ /** This agent's ask summary: the in-memory copy first, else the session's
15729
+ * persisted record (read once per execution). */
15730
+ async loadAskSummary(agentName) {
15731
+ if (this.askSummaries.has(agentName)) return this.askSummaries.get(agentName) ?? void 0;
15732
+ const sessionId = this.askSummarySessionId();
15733
+ const stored = sessionId ? parseAskSummaryRecord(
15734
+ await this.stateStore.getSessionMeta(sessionId, askSummaryMetaKey(agentName))
15735
+ ) : void 0;
15736
+ this.askSummaries.set(agentName, stored ?? null);
15737
+ return stored;
15738
+ }
15739
+ async saveAskSummary(agentName, record) {
15740
+ this.askSummaries.set(agentName, record);
15741
+ const sessionId = this.askSummarySessionId();
15742
+ if (!sessionId) return;
15743
+ const key = askSummaryMetaKey(agentName);
15744
+ try {
15745
+ await this.stateStore.saveSessionMeta(sessionId, key, record);
15746
+ } catch (error) {
15747
+ this.emitEvent({
15748
+ type: "log",
15749
+ agent: agentName,
15750
+ data: {
15751
+ warning: `Could not persist ask summary '${key}' for session '${sessionId}'; later executions will regenerate it. ` + (error instanceof Error ? error.message : String(error))
15752
+ }
15753
+ });
15754
+ }
15755
+ }
15251
15756
  /**
15252
- * Summarize old messages to fit within context window.
15253
- * Keeps recent messages intact, summarizes older ones.
15757
+ * Project `history` into `availableTokens` for one agent's request: a summary
15758
+ * of an exact covered prefix followed by every later message. Reuses the
15759
+ * agent's cached boundary (in memory or persisted for the session) while the
15760
+ * covered prefix, durable session summary, and summary model are unchanged
15761
+ * and the whole tail fits; otherwise generates a new summary. Also reports how
15762
+ * many Anthropic thinking blocks the projection removed from carried turns.
15254
15763
  */
15255
- async summarizeHistory(provider, model, history, availableTokens) {
15256
- if (this.summaryCache) {
15257
- const summaryMsg2 = {
15258
- role: "system",
15259
- origin: "runtime",
15260
- content: `Summary of earlier conversation:
15261
- ${this.summaryCache}`
15262
- };
15263
- const summaryTokens = estimateTokens(summarizeModelInput(summaryMsg2.content)) + 4;
15264
- const remaining = availableTokens - summaryTokens;
15265
- let recentTokens2 = 0;
15266
- let splitIdx2 = history.length;
15267
- for (let i = history.length - 1; i >= 0; i--) {
15268
- const msgTokens = estimateTokens(summarizeModelInput(history[i].content)) + 4;
15269
- if (recentTokens2 + msgTokens > remaining) break;
15270
- recentTokens2 += msgTokens;
15271
- splitIdx2 = i;
15272
- }
15273
- splitIdx2 = nextUserTurn(history, splitIdx2) ?? history.length;
15274
- if (splitIdx2 < history.length) {
15275
- return [summaryMsg2, ...history.slice(splitIdx2)];
15764
+ async summarizeHistory(agentName, modelUri, provider, model, history, availableTokens) {
15765
+ const summaryModelUri = this.config.contextManagement?.summaryModel ?? modelUri;
15766
+ const cache = await this.loadAskSummary(agentName);
15767
+ if (cache && cache.sourceSummary === this.sessionSummary && cache.summaryModelUri === summaryModelUri && cache.coveredCount <= history.length && cache.prefixHash === summaryPrefixHash(history, cache.coveredCount)) {
15768
+ const summaryMsg = summaryContextMessage(cache.summary);
15769
+ const summaryTokens = estimateTokens(summarizeModelInput(summaryMsg.content)) + 4;
15770
+ const tail2 = history.slice(cache.coveredCount);
15771
+ const tailTokens = estimateMessagesTokens(tail2).tokens;
15772
+ if (summaryTokens + tailTokens <= availableTokens && (tail2.length === 0 || tail2[0].role === "user")) {
15773
+ let removedThinkingBlocks = 0;
15774
+ const projected = tail2.map((message, index) => {
15775
+ if (cache.coveredCount + index >= cache.invalidatedThinkingThrough) return message;
15776
+ removedThinkingBlocks += anthropicThinkingBlockCount(message);
15777
+ return withoutAnthropicThinking(message);
15778
+ });
15779
+ return { messages: [summaryMsg, ...projected], removedThinkingBlocks };
15276
15780
  }
15277
15781
  }
15278
15782
  let recentTokens = 0;
@@ -15297,42 +15801,103 @@ ${this.summaryCache}`
15297
15801
  } else {
15298
15802
  splitIdx = history.length;
15299
15803
  }
15300
- if (splitIdx === 0) return history;
15804
+ if (splitIdx === 0 && this.sessionSummary) splitIdx = history.length;
15805
+ if (splitIdx === 0) return { messages: history, removedThinkingBlocks: 0 };
15301
15806
  const oldMessages = history.slice(0, splitIdx);
15302
- const summaryModelUri = this.config.contextManagement?.summaryModel;
15807
+ const configuredSummaryModelUri = this.config.contextManagement?.summaryModel;
15303
15808
  let summaryProvider;
15304
15809
  let summaryModel;
15305
- if (summaryModelUri) {
15306
- const resolved = this.resolveProviderUri(summaryModelUri);
15810
+ if (configuredSummaryModelUri) {
15811
+ const resolved = this.resolveProviderUri(configuredSummaryModelUri);
15307
15812
  summaryProvider = resolved.provider;
15308
15813
  summaryModel = resolved.model;
15309
15814
  } else {
15310
15815
  summaryProvider = provider;
15311
15816
  summaryModel = model;
15312
15817
  }
15313
- const oldContent = oldMessages.map((m) => `${m.role}: ${summarizeModelInput(m.content)}`).join("\n");
15314
- const summaryResponse = await summaryProvider.chat(
15315
- [
15316
- {
15317
- role: "system",
15318
- content: "Summarize the following conversation concisely, preserving key facts, decisions, and context needed for continuing the conversation."
15319
- },
15320
- { role: "user", content: oldContent }
15818
+ const summaryPrompt = buildSummaryPrompt(oldMessages, this.sessionSummary);
15819
+ const summaryStart = Date.now();
15820
+ this.emitEvent({
15821
+ type: "agent_call_start",
15822
+ agent: agentName,
15823
+ model: summaryModelUri,
15824
+ turn: 0,
15825
+ data: {
15826
+ purpose: "summary",
15827
+ prompt: summaryPrompt,
15828
+ system: SUMMARY_SYSTEM_PROMPT,
15829
+ params: { maxTokens: SUMMARY_MAX_TOKENS },
15830
+ turn: 0
15831
+ }
15832
+ });
15833
+ let summaryResponse;
15834
+ try {
15835
+ this.currentSignal?.throwIfAborted();
15836
+ summaryResponse = await requestSummary(summaryProvider, {
15837
+ model: summaryModel,
15838
+ prompt: summaryPrompt,
15839
+ signal: this.currentSignal
15840
+ });
15841
+ } catch (error) {
15842
+ const providerError = error instanceof ProviderError ? error : void 0;
15843
+ this.emitEvent({
15844
+ type: "agent_call_end",
15845
+ agent: agentName,
15846
+ model: summaryModelUri,
15847
+ duration: Date.now() - summaryStart,
15848
+ ...providerError?.timing ? { timing: providerError.timing } : {},
15849
+ data: {
15850
+ purpose: "summary",
15851
+ response: "",
15852
+ turn: 0,
15853
+ // Provider errors may echo the summarized history, so the event
15854
+ // uses a fixed projection even when trace redaction is disabled.
15855
+ error: "Context-management summary call failed",
15856
+ ...providerError ? { status: providerError.status, retryable: providerError.retryable } : {}
15857
+ }
15858
+ });
15859
+ throw error;
15860
+ }
15861
+ if (isUsableCost2(summaryResponse.cost)) this._accumulateBudgetCost(summaryResponse.cost);
15862
+ this.emitEvent({
15863
+ type: "agent_call_end",
15864
+ agent: agentName,
15865
+ model: summaryModelUri,
15866
+ cost: summaryResponse.cost,
15867
+ ...!isUsableCost2(summaryResponse.cost) ? { unpriced: true } : {},
15868
+ tokens: summaryResponse.usage ? {
15869
+ input: summaryResponse.usage.prompt_tokens,
15870
+ output: summaryResponse.usage.completion_tokens,
15871
+ reasoning: summaryResponse.usage.reasoning_tokens,
15872
+ cached: summaryResponse.usage.cached_tokens,
15873
+ cacheWrite: summaryResponse.usage.cache_write_tokens
15874
+ } : void 0,
15875
+ duration: Date.now() - summaryStart,
15876
+ ...summaryResponse.timing ? { timing: summaryResponse.timing } : {},
15877
+ data: { purpose: "summary", response: summaryResponse.content, turn: 0 }
15878
+ });
15879
+ const prefixHash = summaryPrefixHash(history, splitIdx);
15880
+ if (prefixHash) {
15881
+ await this.saveAskSummary(agentName, {
15882
+ summary: summaryResponse.content,
15883
+ coveredCount: splitIdx,
15884
+ prefixHash,
15885
+ ...this.sessionSummary !== void 0 ? { sourceSummary: this.sessionSummary } : {},
15886
+ summaryModelUri,
15887
+ invalidatedThinkingThrough: history.length
15888
+ });
15889
+ }
15890
+ const tail = history.slice(splitIdx);
15891
+ return {
15892
+ messages: [
15893
+ summaryContextMessage(summaryResponse.content),
15894
+ ...tail.map(withoutAnthropicThinking)
15321
15895
  ],
15322
- { model: summaryModel, maxTokens: 1024, signal: this.currentSignal }
15323
- );
15324
- this.summaryCache = summaryResponse.content;
15325
- const sessionId = this.metadata?.sessionId;
15326
- if (sessionId && this.stateStore) {
15327
- await this.stateStore.saveSessionMeta(sessionId, "summaryCache", this.summaryCache);
15328
- }
15329
- const summaryMsg = {
15330
- role: "system",
15331
- origin: "runtime",
15332
- content: `Summary of earlier conversation:
15333
- ${summaryResponse.content}`
15896
+ removedThinkingBlocks: tail.reduce(
15897
+ (count, message) => count + anthropicThinkingBlockCount(message),
15898
+ 0
15899
+ )
15334
15900
  };
15335
- return [summaryMsg, ...history.slice(splitIdx)];
15336
15901
  }
15337
15902
  // ── ctx.checkpoint() ────────────────────────────────────────────────
15338
15903
  /**
@@ -16590,7 +17155,7 @@ ${summaryResponse.content}`
16590
17155
  * This operation never enters the chat history or chat-provider path. */
16591
17156
  async transcribe(request) {
16592
17157
  const startedAt = Date.now();
16593
- const transcriptionId = (0, import_node_crypto.randomUUID)();
17158
+ const transcriptionId = (0, import_node_crypto2.randomUUID)();
16594
17159
  const signal = this.currentSignal;
16595
17160
  const rawAudio = request && typeof request === "object" && "audio" in request ? request.audio : void 0;
16596
17161
  const source = rawAudio?.type;
@@ -16979,7 +17544,7 @@ ${summaryResponse.content}`
16979
17544
  };
16980
17545
 
16981
17546
  // src/agent.ts
16982
- var import_node_crypto2 = require("crypto");
17547
+ var import_node_crypto3 = require("crypto");
16983
17548
  var agentCounter = 0;
16984
17549
  function agent(config) {
16985
17550
  agentCounter++;
@@ -17000,7 +17565,7 @@ function agent(config) {
17000
17565
  const transcriptionRegistry = new TranscriptionProviderRegistry();
17001
17566
  const ctx = new WorkflowContext({
17002
17567
  input: prompt,
17003
- executionId: (0, import_node_crypto2.randomUUID)(),
17568
+ executionId: (0, import_node_crypto3.randomUUID)(),
17004
17569
  config: {},
17005
17570
  providerRegistry: registry2,
17006
17571
  transcriptionProviderRegistry: transcriptionRegistry
@@ -17025,7 +17590,7 @@ function workflow(config) {
17025
17590
 
17026
17591
  // src/runtime.ts
17027
17592
  var import_node_events2 = require("events");
17028
- var import_node_crypto4 = require("crypto");
17593
+ var import_node_crypto5 = require("crypto");
17029
17594
  var import_node_async_hooks4 = require("async_hooks");
17030
17595
  var import_node_fs3 = require("fs");
17031
17596
  var import_node_path3 = require("path");
@@ -17741,17 +18306,17 @@ var Session = class _Session {
17741
18306
  throw new Error("SessionOptions.history.summaryModel is required when summarize is true");
17742
18307
  }
17743
18308
  const messagesToDrop = history.slice(0, history.length - maxMessages);
17744
- const toSummarize = cachedSummary ? [
17745
- { role: "system", content: `Previous conversation summary: ${cachedSummary}` },
17746
- ...messagesToDrop
17747
- ] : messagesToDrop;
17748
- const summary = await this.runtime.summarizeMessages(toSummarize, summaryModel);
18309
+ const summary = await this.runtime.summarizeMessages(
18310
+ messagesToDrop,
18311
+ summaryModel,
18312
+ cachedSummary ? { previousSummary: cachedSummary } : void 0
18313
+ );
17749
18314
  await this.store.saveSessionMeta(this.sessionId, "summaryCache", summary);
17750
18315
  cachedSummary = summary;
17751
18316
  }
17752
18317
  const trimmed = history.slice(-maxMessages);
17753
18318
  history.length = 0;
17754
- history.push(...trimmed);
18319
+ history.push(...trimmed.map(withoutAnthropicThinking));
17755
18320
  }
17756
18321
  const userMessage = { role: "user", content: preparedInput.content };
17757
18322
  history.push(userMessage);
@@ -17761,7 +18326,10 @@ var Session = class _Session {
17761
18326
  const metadata = {
17762
18327
  sessionId: this.sessionId,
17763
18328
  sessionHistory: history,
17764
- ...cachedSummary ? { summaryCache: cachedSummary } : {}
18329
+ ...cachedSummary ? { summaryCache: cachedSummary } : {},
18330
+ // An opted-out session must leave nothing at rest, including the
18331
+ // agent-scoped ask-summary records the runtime would otherwise cache.
18332
+ ...this.options.persist === false ? { sessionPersist: false } : {}
17765
18333
  };
17766
18334
  return { history, metadata };
17767
18335
  }
@@ -18678,7 +19246,7 @@ function warnMissingMemoryMethodsOnce(stateStore) {
18678
19246
  var import_node_fs2 = require("fs");
18679
19247
  var import_promises = require("fs/promises");
18680
19248
  var import_node_readline = require("readline");
18681
- var import_node_crypto3 = require("crypto");
19249
+ var import_node_crypto4 = require("crypto");
18682
19250
  var import_node_path2 = __toESM(require("path"), 1);
18683
19251
  var MANIFEST_FILE = "manifest.json";
18684
19252
  var RECORDS_FILE = "records.jsonl";
@@ -18743,7 +19311,7 @@ var FileDiagnosticArtifactStore = class {
18743
19311
  async writeManifest(manifest) {
18744
19312
  const dir = this.dir(manifest.artifactId);
18745
19313
  await (0, import_promises.mkdir)(dir, { recursive: true });
18746
- const temp = import_node_path2.default.join(dir, `${MANIFEST_FILE}.${(0, import_node_crypto3.randomUUID)()}.tmp`);
19314
+ const temp = import_node_path2.default.join(dir, `${MANIFEST_FILE}.${(0, import_node_crypto4.randomUUID)()}.tmp`);
18747
19315
  await (0, import_promises.writeFile)(temp, JSON.stringify(manifest), "utf-8");
18748
19316
  await (0, import_promises.rename)(temp, import_node_path2.default.join(dir, MANIFEST_FILE));
18749
19317
  }
@@ -18780,7 +19348,7 @@ var FileDiagnosticArtifactStore = class {
18780
19348
  });
18781
19349
  }
18782
19350
  async stage(owner, opts) {
18783
- const artifactId = `art_${(0, import_node_crypto3.randomUUID)()}`;
19351
+ const artifactId = `art_${(0, import_node_crypto4.randomUUID)()}`;
18784
19352
  const now = Date.now();
18785
19353
  await this.writeManifest({
18786
19354
  version: 1,
@@ -19981,7 +20549,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
19981
20549
  }
19982
20550
  try {
19983
20551
  await this.saveEvalResult({
19984
- id: resultObj.id ?? (0, import_node_crypto4.randomUUID)(),
20552
+ id: resultObj.id ?? (0, import_node_crypto5.randomUUID)(),
19985
20553
  eval: name,
19986
20554
  timestamp: Date.now(),
19987
20555
  data: structuredClone(result)
@@ -20039,7 +20607,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
20039
20607
  */
20040
20608
  createContext(options) {
20041
20609
  assertNoRemovedObservationCallbacks(options);
20042
- const executionId = (0, import_node_crypto4.randomUUID)();
20610
+ const executionId = (0, import_node_crypto5.randomUUID)();
20043
20611
  const budgetLimit = options?.budget ? parseCost(options.budget) : Infinity;
20044
20612
  this.registerWithCostScope(executionId);
20045
20613
  return new WorkflowContext({
@@ -20118,7 +20686,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
20118
20686
  }
20119
20687
  const validated = workflow2.inputSchema.parse(input);
20120
20688
  const branchDrainTimeoutMs = resolveBranchDrainTimeoutMs(options?.branchDrainTimeoutMs);
20121
- const executionId = (0, import_node_crypto4.randomUUID)();
20689
+ const executionId = (0, import_node_crypto5.randomUUID)();
20122
20690
  const controller = new AbortController();
20123
20691
  this.abortControllers.set(executionId, controller);
20124
20692
  const cleanupAbortForwarder = forwardAbortSignal(options?.signal, controller);
@@ -20233,7 +20801,7 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
20233
20801
  const controller = new AbortController();
20234
20802
  axlStream.on("close", () => controller.abort());
20235
20803
  const cleanupAbortForwarder = forwardAbortSignal(options?.signal, controller);
20236
- const executionId = (0, import_node_crypto4.randomUUID)();
20804
+ const executionId = (0, import_node_crypto5.randomUUID)();
20237
20805
  this.abortControllers.set(executionId, controller);
20238
20806
  let execInfo;
20239
20807
  let wfCtx;
@@ -20834,22 +21402,17 @@ var AxlRuntime = class extends import_node_events2.EventEmitter {
20834
21402
  /**
20835
21403
  * Summarize a list of chat messages into a concise summary string.
20836
21404
  * Used by Session to summarize dropped messages when history.summarize is enabled.
21405
+ * `previousSummary` is folded in so a rolling summary never loses what it
21406
+ * alone still carries. Shares its prompt and provider call with the
21407
+ * `AgentConfig.maxContext` summarizer (see `compaction.ts`). It runs outside
21408
+ * any workflow execution, so it emits no ask-scoped events.
20837
21409
  */
20838
- async summarizeMessages(messages, modelUri) {
21410
+ async summarizeMessages(messages, modelUri, options) {
20839
21411
  const { provider, model } = this.resolveProvider(modelUri);
20840
- const response = await provider.chat(
20841
- [
20842
- {
20843
- role: "system",
20844
- content: "Summarize the following conversation concisely, preserving key facts, decisions, and context needed for continuing the conversation."
20845
- },
20846
- {
20847
- role: "user",
20848
- content: messages.map((m) => `${m.role}: ${summarizeModelInput(m.content)}`).join("\n")
20849
- }
20850
- ],
20851
- { model, maxTokens: 1024 }
20852
- );
21412
+ const response = await requestSummary(provider, {
21413
+ model,
21414
+ prompt: buildSummaryPrompt(messages, options?.previousSummary)
21415
+ });
20853
21416
  return response.content;
20854
21417
  }
20855
21418
  /** Get the state store (for testing and advanced use cases). */
@@ -22280,6 +22843,7 @@ function cosineSimilarity2(a, b) {
22280
22843
  TranscriptionProviderRegistry,
22281
22844
  UnsupportedEventSchemaVersionError,
22282
22845
  UnsupportedModelInputError,
22846
+ UnsupportedModelOptionError,
22283
22847
  UnsupportedTranscriptionInputError,
22284
22848
  VLLM_PROFILE,
22285
22849
  ValidationError,