@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 +717 -153
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -19
- package/dist/index.d.ts +94 -19
- package/dist/index.js +702 -139
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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.
|
|
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
|
-
|
|
4204
|
-
|
|
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
|
|
4207
|
-
return
|
|
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
|
-
|
|
4210
|
-
"
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
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
|
-
|
|
4219
|
-
|
|
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
|
-
|
|
4222
|
-
|
|
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
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
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
|
|
4234
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
4253
|
-
|
|
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 {
|
|
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
|
|
4581
|
-
const reasoningCapable =
|
|
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 =
|
|
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
|
-
...
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
11173
|
-
//
|
|
11174
|
-
//
|
|
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
|
-
|
|
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.
|
|
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,
|
|
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
|
-
|
|
14005
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
*
|
|
15253
|
-
*
|
|
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
|
-
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
|
|
15260
|
-
|
|
15261
|
-
|
|
15262
|
-
|
|
15263
|
-
|
|
15264
|
-
|
|
15265
|
-
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
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)
|
|
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
|
|
15807
|
+
const configuredSummaryModelUri = this.config.contextManagement?.summaryModel;
|
|
15303
15808
|
let summaryProvider;
|
|
15304
15809
|
let summaryModel;
|
|
15305
|
-
if (
|
|
15306
|
-
const resolved = this.resolveProviderUri(
|
|
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
|
|
15314
|
-
const
|
|
15315
|
-
|
|
15316
|
-
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
|
|
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
|
-
|
|
15323
|
-
|
|
15324
|
-
|
|
15325
|
-
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17748
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
20841
|
-
|
|
20842
|
-
|
|
20843
|
-
|
|
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,
|