@axlsdk/axl 0.24.3 → 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 +768 -187
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +96 -19
- package/dist/index.d.ts +96 -19
- package/dist/index.js +753 -173
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -40,6 +40,23 @@ var UnsupportedModelInputError = class extends AxlError {
|
|
|
40
40
|
this.source = options.source;
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
|
+
var UnsupportedModelOptionError = class extends AxlError {
|
|
44
|
+
provider;
|
|
45
|
+
model;
|
|
46
|
+
option;
|
|
47
|
+
remediation;
|
|
48
|
+
constructor(options) {
|
|
49
|
+
super(
|
|
50
|
+
"UNSUPPORTED_MODEL_OPTION",
|
|
51
|
+
`Provider '${options.provider}' model '${options.model}' does not support ${options.option}. ${options.remediation}`
|
|
52
|
+
);
|
|
53
|
+
this.name = "UnsupportedModelOptionError";
|
|
54
|
+
this.provider = options.provider;
|
|
55
|
+
this.model = options.model;
|
|
56
|
+
this.option = options.option;
|
|
57
|
+
this.remediation = options.remediation;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
43
60
|
var InvalidTranscriptionInputError = class extends AxlError {
|
|
44
61
|
constructor(message) {
|
|
45
62
|
super("INVALID_TRANSCRIPTION_INPUT", message);
|
|
@@ -193,7 +210,7 @@ var TimeoutError = class extends AxlError {
|
|
|
193
210
|
constructor(operation, timeoutMs, breakdown, agent2) {
|
|
194
211
|
super(
|
|
195
212
|
"TIMEOUT",
|
|
196
|
-
`${operation} exceeded timeout of ${timeoutMs}ms` + (breakdown ? ` (elapsed ${breakdown.elapsedMs}ms: queued ${breakdown.queuedMs}ms, retries ${breakdown.retryMs}ms, wire ${breakdown.wireMs}ms, other ${breakdown.otherMs}ms)` : "") + (agent2 ? ` for agent '${agent2}'` : "")
|
|
213
|
+
`${operation} exceeded timeout of ${timeoutMs}ms` + (breakdown ? ` (elapsed ${breakdown.elapsedMs}ms: queued ${breakdown.queuedMs}ms, retries ${breakdown.retryMs}ms, wire ${breakdown.wireMs}ms, other ${breakdown.otherMs}ms, charged ${breakdown.chargedMs}ms)` : "") + (agent2 ? ` for agent '${agent2}'` : "")
|
|
197
214
|
);
|
|
198
215
|
this.name = "TimeoutError";
|
|
199
216
|
if (breakdown) this.breakdown = breakdown;
|
|
@@ -331,7 +348,7 @@ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null
|
|
|
331
348
|
var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
|
|
332
349
|
var thisCopy = {
|
|
333
350
|
path: buildPath.startsWith("file:") ? fileURLToPath(buildPath) : buildPath,
|
|
334
|
-
version: true ? "0.
|
|
351
|
+
version: true ? "0.25.1" : "unknown"
|
|
335
352
|
};
|
|
336
353
|
function warnCrossCopy(other, joined) {
|
|
337
354
|
if (other === thisCopy) return;
|
|
@@ -1315,6 +1332,41 @@ var OPENAI_DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
|
1315
1332
|
var ANTHROPIC_DEFAULT_BASE_URL = "https://api.anthropic.com/v1";
|
|
1316
1333
|
var GEMINI_DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
1317
1334
|
|
|
1335
|
+
// src/ask-clock.ts
|
|
1336
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
1337
|
+
var askClockStorage = new AsyncLocalStorage2();
|
|
1338
|
+
function runWithAskClock(fn) {
|
|
1339
|
+
const tracker = { pausedMs: 0, activePauses: 0 };
|
|
1340
|
+
const enclosing = askClockStorage.getStore() ?? [];
|
|
1341
|
+
return askClockStorage.run([...enclosing, tracker], fn);
|
|
1342
|
+
}
|
|
1343
|
+
function currentAskClock() {
|
|
1344
|
+
return askClockStorage.getStore()?.at(-1);
|
|
1345
|
+
}
|
|
1346
|
+
function pausedAskClockMs(tracker, now = Date.now()) {
|
|
1347
|
+
return tracker.pausedMs + (tracker.activePauses > 0 && tracker.pauseStartedAt !== void 0 ? now - tracker.pauseStartedAt : 0);
|
|
1348
|
+
}
|
|
1349
|
+
async function pauseAskClocks(wait) {
|
|
1350
|
+
const trackers = askClockStorage.getStore();
|
|
1351
|
+
if (!trackers || trackers.length === 0) return wait();
|
|
1352
|
+
const startedAt = Date.now();
|
|
1353
|
+
for (const tracker of trackers) {
|
|
1354
|
+
if (tracker.activePauses++ === 0) tracker.pauseStartedAt = startedAt;
|
|
1355
|
+
}
|
|
1356
|
+
try {
|
|
1357
|
+
return await wait();
|
|
1358
|
+
} finally {
|
|
1359
|
+
const finishedAt = Date.now();
|
|
1360
|
+
for (const tracker of trackers) {
|
|
1361
|
+
tracker.activePauses--;
|
|
1362
|
+
if (tracker.activePauses === 0 && tracker.pauseStartedAt !== void 0) {
|
|
1363
|
+
tracker.pausedMs += finishedAt - tracker.pauseStartedAt;
|
|
1364
|
+
tracker.pauseStartedAt = void 0;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1318
1370
|
// src/providers/rate-limiter.ts
|
|
1319
1371
|
function sanitizeRateLimitConfig(config) {
|
|
1320
1372
|
const limits = {};
|
|
@@ -2377,7 +2429,7 @@ async function fetchWithRetry(input, init, opts) {
|
|
|
2377
2429
|
let headersAt = 0;
|
|
2378
2430
|
const waitSelfImposed = async (wait) => {
|
|
2379
2431
|
const start = Date.now();
|
|
2380
|
-
await wait
|
|
2432
|
+
await pauseAskClocks(wait);
|
|
2381
2433
|
const waited = Date.now() - start;
|
|
2382
2434
|
queuedMs += waited;
|
|
2383
2435
|
if (dispatches > 0) queuedAfterFirstDispatchMs += waited;
|
|
@@ -3169,8 +3221,12 @@ var OpenAICompatibleProvider = class {
|
|
|
3169
3221
|
for (const key of forbidden) {
|
|
3170
3222
|
if (!userKeys.includes(key)) delete body[key];
|
|
3171
3223
|
}
|
|
3224
|
+
this.validateFinalRequestBody(body);
|
|
3172
3225
|
return body;
|
|
3173
3226
|
}
|
|
3227
|
+
/** Native subclasses may reject model-invalid fields after providerOptions merge. */
|
|
3228
|
+
validateFinalRequestBody(_body) {
|
|
3229
|
+
}
|
|
3174
3230
|
formatMessage(msg, model) {
|
|
3175
3231
|
const modalities = this.inputModalities(model);
|
|
3176
3232
|
const out = {
|
|
@@ -3578,6 +3634,24 @@ var withLongContext = (short) => ({
|
|
|
3578
3634
|
output: short.output * 1.5
|
|
3579
3635
|
});
|
|
3580
3636
|
var DIRECT_OPENAI_CATALOG = [
|
|
3637
|
+
{
|
|
3638
|
+
aliases: ["gpt-6-astra"],
|
|
3639
|
+
short: { input: 10 / M, cachedInput: 1 / M, cacheWrite: 12.5 / M, output: 50 / M },
|
|
3640
|
+
long: { input: 20 / M, cachedInput: 2 / M, cacheWrite: 25 / M, output: 75 / M },
|
|
3641
|
+
contextBoundary: LONG_CONTEXT_BOUNDARY
|
|
3642
|
+
},
|
|
3643
|
+
{
|
|
3644
|
+
aliases: ["gpt-6-sol"],
|
|
3645
|
+
short: { input: 2 / M, cachedInput: 0.2 / M, cacheWrite: 2.5 / M, output: 10 / M },
|
|
3646
|
+
long: { input: 4 / M, cachedInput: 0.4 / M, cacheWrite: 5 / M, output: 15 / M },
|
|
3647
|
+
contextBoundary: LONG_CONTEXT_BOUNDARY
|
|
3648
|
+
},
|
|
3649
|
+
{
|
|
3650
|
+
aliases: ["gpt-6-luna"],
|
|
3651
|
+
short: { input: 0.1 / M, cachedInput: 0.01 / M, cacheWrite: 0.125 / M, output: 0.5 / M },
|
|
3652
|
+
long: { input: 0.2 / M, cachedInput: 0.02 / M, cacheWrite: 0.25 / M, output: 0.75 / M },
|
|
3653
|
+
contextBoundary: LONG_CONTEXT_BOUNDARY
|
|
3654
|
+
},
|
|
3581
3655
|
{
|
|
3582
3656
|
aliases: ["gpt-5.6", "gpt-5.6-sol"],
|
|
3583
3657
|
snapshotBase: "gpt-5.6-sol",
|
|
@@ -3908,7 +3982,7 @@ function estimateDirectOpenAICost(model, usage, context) {
|
|
|
3908
3982
|
const audioOutput = audio_output_tokens ?? 0;
|
|
3909
3983
|
if (![prompt_tokens, completion_tokens, cached, cacheWrite, audioInput, audioOutput].every(
|
|
3910
3984
|
(count) => Number.isSafeInteger(count) && count >= 0
|
|
3911
|
-
) || cached + cacheWrite + audioInput > prompt_tokens || audioOutput > completion_tokens) {
|
|
3985
|
+
) || resolveOpenAIModelDescriptor(model).strictUsageTotals && (!Number.isSafeInteger(usage.total_tokens) || usage.total_tokens !== prompt_tokens + completion_tokens) || cached + cacheWrite + audioInput > prompt_tokens || audioOutput > completion_tokens) {
|
|
3912
3986
|
return void 0;
|
|
3913
3987
|
}
|
|
3914
3988
|
if (audioInput > 0 && entry.audio === void 0 || audioOutput > 0 && entry.audio?.output === void 0) {
|
|
@@ -3933,57 +4007,206 @@ function estimateOpenAICost(model, promptTokens, completionTokens, cachedTokens)
|
|
|
3933
4007
|
cached_tokens: cachedTokens
|
|
3934
4008
|
});
|
|
3935
4009
|
}
|
|
3936
|
-
|
|
3937
|
-
|
|
4010
|
+
var EFFORT_FALLBACK = {
|
|
4011
|
+
none: "minimal",
|
|
4012
|
+
minimal: "low",
|
|
4013
|
+
low: "medium",
|
|
4014
|
+
medium: "high",
|
|
4015
|
+
max: "xhigh",
|
|
4016
|
+
xhigh: "high"
|
|
4017
|
+
};
|
|
4018
|
+
var BASE_EFFORTS = ["minimal", "low", "medium", "high"];
|
|
4019
|
+
function bothEndpoints(value) {
|
|
4020
|
+
return { chat: value, responses: value };
|
|
3938
4021
|
}
|
|
3939
|
-
function
|
|
3940
|
-
return
|
|
4022
|
+
function gpt6(id, efforts, chatTools) {
|
|
4023
|
+
return {
|
|
4024
|
+
id,
|
|
4025
|
+
family: "gpt-6",
|
|
4026
|
+
reasoning: true,
|
|
4027
|
+
efforts: bothEndpoints(efforts),
|
|
4028
|
+
defaultEffort: "medium",
|
|
4029
|
+
// Same policy as GPT-5.x: a portable `temperature` is dropped while
|
|
4030
|
+
// reasoning is active (including the active default). A raw
|
|
4031
|
+
// `providerOptions` sampling field is rejected by the final-body check.
|
|
4032
|
+
sampling: bothEndpoints("unless-effort-none"),
|
|
4033
|
+
chatTools,
|
|
4034
|
+
validatesFinalBody: true,
|
|
4035
|
+
strictUsageTotals: true
|
|
4036
|
+
};
|
|
3941
4037
|
}
|
|
3942
|
-
|
|
3943
|
-
"
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
4038
|
+
function gpt56(id) {
|
|
4039
|
+
const chat = ["none", ...BASE_EFFORTS, "xhigh"];
|
|
4040
|
+
return {
|
|
4041
|
+
id,
|
|
4042
|
+
family: "gpt-5.6",
|
|
4043
|
+
reasoning: true,
|
|
4044
|
+
efforts: { chat, responses: [...chat, "max"] },
|
|
4045
|
+
// Responses rejects temperature even at the provider-default effort.
|
|
4046
|
+
sampling: { chat: "when-effort-sent", responses: "always" },
|
|
4047
|
+
chatTools: "allowed",
|
|
4048
|
+
validatesFinalBody: false,
|
|
4049
|
+
strictUsageTotals: false
|
|
4050
|
+
};
|
|
3950
4051
|
}
|
|
3951
|
-
|
|
3952
|
-
|
|
4052
|
+
var OPENAI_EXACT_MODELS = new Map(
|
|
4053
|
+
[
|
|
4054
|
+
gpt6("gpt-6-astra", ["low", "medium", "high", "xhigh", "max"], "never"),
|
|
4055
|
+
gpt6("gpt-6-sol", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
|
|
4056
|
+
gpt6("gpt-6-luna", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
|
|
4057
|
+
gpt56("gpt-5.6"),
|
|
4058
|
+
gpt56("gpt-5.6-sol"),
|
|
4059
|
+
gpt56("gpt-5.6-terra"),
|
|
4060
|
+
gpt56("gpt-5.6-luna")
|
|
4061
|
+
].map((descriptor) => [descriptor.id, descriptor])
|
|
4062
|
+
);
|
|
4063
|
+
var O_SERIES_DESCRIPTOR = {
|
|
4064
|
+
id: "o-series",
|
|
4065
|
+
family: "o-series",
|
|
4066
|
+
reasoning: true,
|
|
4067
|
+
efforts: bothEndpoints(BASE_EFFORTS),
|
|
4068
|
+
defaultEffort: "medium",
|
|
4069
|
+
sampling: bothEndpoints("always"),
|
|
4070
|
+
chatTools: "allowed",
|
|
4071
|
+
validatesFinalBody: false,
|
|
4072
|
+
strictUsageTotals: false
|
|
4073
|
+
};
|
|
4074
|
+
var GPT_5_PRO_DESCRIPTOR = {
|
|
4075
|
+
id: "gpt-5-pro",
|
|
4076
|
+
family: "gpt-5-pro",
|
|
4077
|
+
reasoning: true,
|
|
4078
|
+
efforts: bothEndpoints(["high"]),
|
|
4079
|
+
defaultEffort: "high",
|
|
4080
|
+
sampling: bothEndpoints("when-effort-sent"),
|
|
4081
|
+
chatTools: "allowed",
|
|
4082
|
+
validatesFinalBody: false,
|
|
4083
|
+
strictUsageTotals: false
|
|
4084
|
+
};
|
|
4085
|
+
var DEFAULT_DESCRIPTOR = {
|
|
4086
|
+
id: "default",
|
|
4087
|
+
family: "default",
|
|
4088
|
+
reasoning: false,
|
|
4089
|
+
// Never emitted (the model is not reasoning-capable); keeps the clamp total.
|
|
4090
|
+
efforts: bothEndpoints(BASE_EFFORTS),
|
|
4091
|
+
sampling: bothEndpoints("never"),
|
|
4092
|
+
chatTools: "allowed",
|
|
4093
|
+
validatesFinalBody: false,
|
|
4094
|
+
strictUsageTotals: false
|
|
4095
|
+
};
|
|
4096
|
+
function gpt5FamilyDescriptor(model) {
|
|
4097
|
+
const none = /^gpt-5\.[1-9]/.test(model);
|
|
4098
|
+
const xhigh = /^gpt-5\.([2-9]|\d{2,})/.test(model);
|
|
4099
|
+
const efforts = [
|
|
4100
|
+
...none ? ["none"] : [],
|
|
4101
|
+
...BASE_EFFORTS,
|
|
4102
|
+
...xhigh ? ["xhigh"] : []
|
|
4103
|
+
];
|
|
4104
|
+
return {
|
|
4105
|
+
id: "gpt-5",
|
|
4106
|
+
family: "gpt-5",
|
|
4107
|
+
reasoning: true,
|
|
4108
|
+
efforts: bothEndpoints(efforts),
|
|
4109
|
+
...none ? {} : { defaultEffort: "medium" },
|
|
4110
|
+
sampling: bothEndpoints("when-effort-sent"),
|
|
4111
|
+
chatTools: "allowed",
|
|
4112
|
+
validatesFinalBody: false,
|
|
4113
|
+
strictUsageTotals: false
|
|
4114
|
+
};
|
|
3953
4115
|
}
|
|
3954
|
-
|
|
3955
|
-
|
|
4116
|
+
var OPENAI_FAMILY_FALLBACKS = [
|
|
4117
|
+
{ match: /^(o1|o3|o4-mini)/, describe: () => O_SERIES_DESCRIPTOR },
|
|
4118
|
+
{ match: /^gpt-5-pro/, describe: () => GPT_5_PRO_DESCRIPTOR },
|
|
4119
|
+
{ match: /^gpt-5/, describe: gpt5FamilyDescriptor }
|
|
4120
|
+
];
|
|
4121
|
+
function resolveOpenAIModelDescriptor(model) {
|
|
4122
|
+
const exact = OPENAI_EXACT_MODELS.get(model);
|
|
4123
|
+
if (exact) return exact;
|
|
4124
|
+
const family = OPENAI_FAMILY_FALLBACKS.find((entry) => entry.match.test(model));
|
|
4125
|
+
return family ? family.describe(model) : DEFAULT_DESCRIPTOR;
|
|
4126
|
+
}
|
|
4127
|
+
function clampToDescriptor(descriptor, endpoint, effort) {
|
|
4128
|
+
const accepted = descriptor.efforts[endpoint];
|
|
4129
|
+
let candidate = effort;
|
|
4130
|
+
while (candidate !== void 0 && !accepted.includes(candidate)) {
|
|
4131
|
+
candidate = EFFORT_FALLBACK[candidate];
|
|
4132
|
+
}
|
|
4133
|
+
if (candidate === void 0) {
|
|
4134
|
+
throw new Error(
|
|
4135
|
+
`OpenAI descriptor '${descriptor.id}' accepts no ${endpoint} effort reachable from '${effort}'`
|
|
4136
|
+
);
|
|
4137
|
+
}
|
|
4138
|
+
return candidate;
|
|
3956
4139
|
}
|
|
3957
|
-
function
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
4140
|
+
function stripsPortableSampling(descriptor, endpoint, wireEffort) {
|
|
4141
|
+
switch (descriptor.sampling[endpoint]) {
|
|
4142
|
+
case "never":
|
|
4143
|
+
return false;
|
|
4144
|
+
case "always":
|
|
4145
|
+
return true;
|
|
4146
|
+
case "when-effort-sent":
|
|
4147
|
+
return wireEffort !== void 0;
|
|
4148
|
+
case "unless-effort-none":
|
|
4149
|
+
return (wireEffort ?? descriptor.defaultEffort) !== "none";
|
|
3962
4150
|
}
|
|
3963
|
-
if (effort === "xhigh" && !supportsXhigh(model)) return "high";
|
|
3964
|
-
return effort;
|
|
3965
4151
|
}
|
|
3966
|
-
function
|
|
3967
|
-
return
|
|
4152
|
+
function isOSeriesModel(model) {
|
|
4153
|
+
return resolveOpenAIModelDescriptor(model).family === "o-series";
|
|
3968
4154
|
}
|
|
3969
4155
|
function budgetToReasoningEffort(budget) {
|
|
3970
4156
|
if (budget <= 1024) return "low";
|
|
3971
4157
|
if (budget <= 8192) return "medium";
|
|
3972
4158
|
return "high";
|
|
3973
4159
|
}
|
|
4160
|
+
function resolveEndpointReasoningEffort(model, endpoint, resolved) {
|
|
4161
|
+
const descriptor = resolveOpenAIModelDescriptor(model);
|
|
4162
|
+
if (!descriptor.reasoning) return void 0;
|
|
4163
|
+
const requested = resolved.hasBudgetOverride ? budgetToReasoningEffort(resolved.thinkingBudget) : !resolved.thinkingDisabled && resolved.activeEffort ? resolved.activeEffort : resolved.thinkingDisabled ? "none" : void 0;
|
|
4164
|
+
return requested === void 0 ? void 0 : clampToDescriptor(descriptor, endpoint, requested);
|
|
4165
|
+
}
|
|
3974
4166
|
function resolveOpenAIReasoningEffort(model, resolved) {
|
|
3975
|
-
|
|
3976
|
-
if (resolved.hasBudgetOverride) {
|
|
3977
|
-
return clampReasoningEffort(model, budgetToReasoningEffort(resolved.thinkingBudget));
|
|
3978
|
-
}
|
|
3979
|
-
if (!resolved.thinkingDisabled && resolved.activeEffort) {
|
|
3980
|
-
return clampReasoningEffort(model, effortToReasoningEffort(resolved.activeEffort, model));
|
|
3981
|
-
}
|
|
3982
|
-
return resolved.thinkingDisabled ? clampReasoningEffort(model, "none") : void 0;
|
|
4167
|
+
return resolveEndpointReasoningEffort(model, "responses", resolved);
|
|
3983
4168
|
}
|
|
3984
4169
|
function resolveOpenAIChatReasoningEffort(model, resolved) {
|
|
3985
|
-
|
|
3986
|
-
|
|
4170
|
+
return resolveEndpointReasoningEffort(model, "chat", resolved);
|
|
4171
|
+
}
|
|
4172
|
+
function validateOpenAIFinalRequestBody(body, endpoint) {
|
|
4173
|
+
const model = body.model;
|
|
4174
|
+
if (typeof model !== "string") return;
|
|
4175
|
+
const descriptor = resolveOpenAIModelDescriptor(model);
|
|
4176
|
+
if (!descriptor.validatesFinalBody) return;
|
|
4177
|
+
const provider = endpoint === "chat" ? "openai" : "openai-responses";
|
|
4178
|
+
const fail = (option, remediation) => {
|
|
4179
|
+
throw new UnsupportedModelOptionError({ provider, model, option, remediation });
|
|
4180
|
+
};
|
|
4181
|
+
const rawEffort = endpoint === "chat" ? body.reasoning_effort : body.reasoning !== null && typeof body.reasoning === "object" ? body.reasoning.effort : void 0;
|
|
4182
|
+
const accepted = descriptor.efforts[endpoint];
|
|
4183
|
+
if (rawEffort !== void 0 && !accepted.includes(rawEffort)) {
|
|
4184
|
+
fail("reasoning effort", `Use one of: ${accepted.join(", ")}.`);
|
|
4185
|
+
}
|
|
4186
|
+
const activeReasoning = (rawEffort ?? descriptor.defaultEffort) !== "none";
|
|
4187
|
+
if (endpoint === "chat" && descriptor.chatTools !== "allowed") {
|
|
4188
|
+
const toolChoice = body.tool_choice;
|
|
4189
|
+
const toolIntent = Array.isArray(body.tools) && body.tools.length > 0 || toolChoice !== void 0 && toolChoice !== null && toolChoice !== "none" && toolChoice !== "auto";
|
|
4190
|
+
if (toolIntent && (descriptor.chatTools === "never" || activeReasoning)) {
|
|
4191
|
+
fail(
|
|
4192
|
+
"Chat Completions tool calling",
|
|
4193
|
+
descriptor.chatTools === "never" ? `Use openai-responses:${model} for tools.` : `Use openai-responses:${model} for reasoning with tools, or set effective reasoning_effort to 'none'.`
|
|
4194
|
+
);
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
if (activeReasoning) {
|
|
4198
|
+
const forbidden = endpoint === "chat" ? ["temperature", "top_p", "top_logprobs", "logprobs"] : ["temperature", "top_p", "top_logprobs"];
|
|
4199
|
+
for (const key of forbidden) {
|
|
4200
|
+
if (body[key] !== void 0)
|
|
4201
|
+
fail(key, `Remove ${key} or set reasoning effort to 'none' on Sol or Luna.`);
|
|
4202
|
+
}
|
|
4203
|
+
if (endpoint === "responses" && Array.isArray(body.include) && body.include.includes("message.output_text.logprobs")) {
|
|
4204
|
+
fail(
|
|
4205
|
+
"message.output_text.logprobs",
|
|
4206
|
+
"Remove it from include or set reasoning effort to none on Sol or Luna."
|
|
4207
|
+
);
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
3987
4210
|
}
|
|
3988
4211
|
function resolveOpenAIEffortResolution(options, resolveWireEffort, endpoint) {
|
|
3989
4212
|
const resolved = resolveThinkingOptions(options);
|
|
@@ -3999,11 +4222,15 @@ function resolveOpenAIEffortResolution(options, resolveWireEffort, endpoint) {
|
|
|
3999
4222
|
};
|
|
4000
4223
|
}
|
|
4001
4224
|
var openaiReasoningEmit = (body, resolved, model) => {
|
|
4002
|
-
const oSeries = isOSeriesModel(model);
|
|
4003
|
-
const reasoningCapable = supportsReasoningEffort(model);
|
|
4004
4225
|
const wireEffort = resolveOpenAIChatReasoningEffort(model, resolved);
|
|
4005
4226
|
if (wireEffort) body.reasoning_effort = wireEffort;
|
|
4006
|
-
return {
|
|
4227
|
+
return {
|
|
4228
|
+
stripTemperature: stripsPortableSampling(
|
|
4229
|
+
resolveOpenAIModelDescriptor(model),
|
|
4230
|
+
"chat",
|
|
4231
|
+
wireEffort
|
|
4232
|
+
)
|
|
4233
|
+
};
|
|
4007
4234
|
};
|
|
4008
4235
|
var OPENAI_PROFILE = {
|
|
4009
4236
|
name: "openai",
|
|
@@ -4038,6 +4265,9 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
|
|
|
4038
4265
|
"OpenAI Chat Completions"
|
|
4039
4266
|
);
|
|
4040
4267
|
}
|
|
4268
|
+
validateFinalRequestBody(body) {
|
|
4269
|
+
validateOpenAIFinalRequestBody(body, "chat");
|
|
4270
|
+
}
|
|
4041
4271
|
computeCost(model, usage, _reportedCost, context) {
|
|
4042
4272
|
return usage ? estimateDirectOpenAICost(model, usage, { ...context, baseUrl: this.baseUrl }) : void 0;
|
|
4043
4273
|
}
|
|
@@ -4310,12 +4540,12 @@ var OpenAIResponsesProvider = class {
|
|
|
4310
4540
|
// ---------------------------------------------------------------------------
|
|
4311
4541
|
buildRequestBody(messages, options, stream) {
|
|
4312
4542
|
const effectiveModel = typeof options.providerOptions?.model === "string" ? options.providerOptions.model : options.model;
|
|
4313
|
-
const
|
|
4314
|
-
const reasoningCapable =
|
|
4543
|
+
const descriptor = resolveOpenAIModelDescriptor(effectiveModel);
|
|
4544
|
+
const reasoningCapable = descriptor.reasoning;
|
|
4315
4545
|
const resolved = resolveThinkingOptions(options);
|
|
4316
4546
|
const { includeThoughts } = resolved;
|
|
4317
4547
|
const wireEffort = resolveOpenAIReasoningEffort(effectiveModel, resolved);
|
|
4318
|
-
const stripTemp =
|
|
4548
|
+
const stripTemp = stripsPortableSampling(descriptor, "responses", wireEffort);
|
|
4319
4549
|
const systemMessages = messages.filter((m) => m.role === "system");
|
|
4320
4550
|
const nonSystemMessages = messages.filter((m) => m.role !== "system");
|
|
4321
4551
|
const body = {
|
|
@@ -4364,6 +4594,7 @@ var OpenAIResponsesProvider = class {
|
|
|
4364
4594
|
if (options.providerOptions) {
|
|
4365
4595
|
Object.assign(body, options.providerOptions);
|
|
4366
4596
|
}
|
|
4597
|
+
validateOpenAIFinalRequestBody(body, "responses");
|
|
4367
4598
|
return body;
|
|
4368
4599
|
}
|
|
4369
4600
|
requestModel(body, fallback) {
|
|
@@ -4678,6 +4909,36 @@ function anthropicImageBlocks(parts, model) {
|
|
|
4678
4909
|
}
|
|
4679
4910
|
var ANTHROPIC_API_VERSION = "2023-06-01";
|
|
4680
4911
|
var ANTHROPIC_FILES_BETA = "files-api-2025-04-14";
|
|
4912
|
+
var ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
|
|
4913
|
+
function isRecord(value) {
|
|
4914
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4915
|
+
}
|
|
4916
|
+
function hasReplayedThinking(body) {
|
|
4917
|
+
return Array.isArray(body.messages) && body.messages.some(
|
|
4918
|
+
(message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
|
|
4919
|
+
(block) => isRecord(block) && (block.type === "thinking" || block.type === "redacted_thinking")
|
|
4920
|
+
)
|
|
4921
|
+
);
|
|
4922
|
+
}
|
|
4923
|
+
function hasFinalFileImage(body) {
|
|
4924
|
+
return Array.isArray(body.messages) && body.messages.some(
|
|
4925
|
+
(message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
|
|
4926
|
+
(block) => isRecord(block) && block.type === "image" && isRecord(block.source) && block.source.type === "file"
|
|
4927
|
+
)
|
|
4928
|
+
);
|
|
4929
|
+
}
|
|
4930
|
+
function normalizeThinkingDrops(value) {
|
|
4931
|
+
if (!Array.isArray(value)) return void 0;
|
|
4932
|
+
const reasons = {};
|
|
4933
|
+
let droppedBlocks = 0;
|
|
4934
|
+
for (const entry of value) {
|
|
4935
|
+
if (!isRecord(entry) || entry.type !== "thinking_dropped") continue;
|
|
4936
|
+
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";
|
|
4937
|
+
reasons[reason] = (reasons[reason] ?? 0) + 1;
|
|
4938
|
+
droppedBlocks++;
|
|
4939
|
+
}
|
|
4940
|
+
return droppedBlocks > 0 ? { droppedBlocks, reasons } : void 0;
|
|
4941
|
+
}
|
|
4681
4942
|
function hasAnthropicProviderFileImage(messages) {
|
|
4682
4943
|
return messages.some(
|
|
4683
4944
|
(message) => Array.isArray(message.content) && message.content.some(
|
|
@@ -4686,11 +4947,19 @@ function hasAnthropicProviderFileImage(messages) {
|
|
|
4686
4947
|
);
|
|
4687
4948
|
}
|
|
4688
4949
|
var CLAUDE_CAPABILITIES = {
|
|
4950
|
+
"claude-opus-5-5": {
|
|
4951
|
+
thinking: "adaptive-always-on",
|
|
4952
|
+
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
4953
|
+
manualBudget: false,
|
|
4954
|
+
stripTemperature: true,
|
|
4955
|
+
thinkingBinding: true
|
|
4956
|
+
},
|
|
4689
4957
|
"claude-fable-5-1": {
|
|
4690
4958
|
thinking: "adaptive-always-on",
|
|
4691
4959
|
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
4692
4960
|
manualBudget: false,
|
|
4693
|
-
stripTemperature: true
|
|
4961
|
+
stripTemperature: true,
|
|
4962
|
+
thinkingBinding: true
|
|
4694
4963
|
},
|
|
4695
4964
|
"claude-fable-5": {
|
|
4696
4965
|
thinking: "adaptive-always-on",
|
|
@@ -4784,6 +5053,7 @@ function resolveClaudeCapability(model) {
|
|
|
4784
5053
|
}
|
|
4785
5054
|
var DEFAULT_CACHE_READ_MULTIPLIER = 0.1;
|
|
4786
5055
|
var ANTHROPIC_RATES = {
|
|
5056
|
+
"claude-opus-5-5": { input: 4e-6, output: 2e-5, cacheReadMultiplier: 0.05 },
|
|
4787
5057
|
"claude-fable-5-1": { input: 1e-5, output: 5e-5, cacheReadMultiplier: 0.025 },
|
|
4788
5058
|
"claude-fable-5": { input: 1e-5, output: 5e-5 },
|
|
4789
5059
|
// Limited availability (Glasswing). Priced from the public pricing table; no
|
|
@@ -5218,11 +5488,12 @@ var AnthropicProvider = class {
|
|
|
5218
5488
|
// chat - non-streaming completion
|
|
5219
5489
|
// ---------------------------------------------------------------------------
|
|
5220
5490
|
async chat(messages, options) {
|
|
5491
|
+
const body = this.buildRequestBody(messages, options, false);
|
|
5221
5492
|
const headers = this.buildHeaders(
|
|
5222
5493
|
await this.resolveKey(),
|
|
5223
|
-
hasAnthropicProviderFileImage(messages)
|
|
5494
|
+
hasAnthropicProviderFileImage(messages) || hasFinalFileImage(body),
|
|
5495
|
+
this.requiresBindingBeta(body)
|
|
5224
5496
|
);
|
|
5225
|
-
const body = this.buildRequestBody(messages, options, false);
|
|
5226
5497
|
const pricingContext = pricingContextFromBody(body);
|
|
5227
5498
|
const recorder = new CallTimingRecorder(options.requestLifecycle);
|
|
5228
5499
|
const governor = this.governorFor(pricingContext.model ?? options.model);
|
|
@@ -5260,11 +5531,12 @@ var AnthropicProvider = class {
|
|
|
5260
5531
|
// stream - SSE streaming completion
|
|
5261
5532
|
// ---------------------------------------------------------------------------
|
|
5262
5533
|
async *stream(messages, options) {
|
|
5534
|
+
const body = this.buildRequestBody(messages, options, true);
|
|
5263
5535
|
const headers = this.buildHeaders(
|
|
5264
5536
|
await this.resolveKey(),
|
|
5265
|
-
hasAnthropicProviderFileImage(messages)
|
|
5537
|
+
hasAnthropicProviderFileImage(messages) || hasFinalFileImage(body),
|
|
5538
|
+
this.requiresBindingBeta(body)
|
|
5266
5539
|
);
|
|
5267
|
-
const body = this.buildRequestBody(messages, options, true);
|
|
5268
5540
|
const pricingContext = pricingContextFromBody(body);
|
|
5269
5541
|
const recorder = new CallTimingRecorder(options.requestLifecycle);
|
|
5270
5542
|
const governor = this.governorFor(pricingContext.model ?? options.model);
|
|
@@ -5306,12 +5578,61 @@ var AnthropicProvider = class {
|
|
|
5306
5578
|
// ---------------------------------------------------------------------------
|
|
5307
5579
|
// Internal: request building
|
|
5308
5580
|
// ---------------------------------------------------------------------------
|
|
5309
|
-
buildHeaders(apiKey, requiresFilesBeta = false) {
|
|
5581
|
+
buildHeaders(apiKey, requiresFilesBeta = false, requiresBindingBeta = false) {
|
|
5582
|
+
const betas = [
|
|
5583
|
+
...requiresFilesBeta ? [ANTHROPIC_FILES_BETA] : [],
|
|
5584
|
+
...requiresBindingBeta ? [ANTHROPIC_THINKING_BINDING_BETA] : []
|
|
5585
|
+
];
|
|
5310
5586
|
return {
|
|
5311
5587
|
"Content-Type": "application/json",
|
|
5312
5588
|
"x-api-key": apiKey,
|
|
5313
5589
|
"anthropic-version": ANTHROPIC_API_VERSION,
|
|
5314
|
-
...
|
|
5590
|
+
...betas.length > 0 ? { "anthropic-beta": betas.join(",") } : {}
|
|
5591
|
+
};
|
|
5592
|
+
}
|
|
5593
|
+
requiresBindingBeta(body) {
|
|
5594
|
+
const thinking = body.thinking;
|
|
5595
|
+
return resolveClaudeCapability(String(body.model))?.thinkingBinding === true && (hasReplayedThinking(body) || isRecord(thinking) && thinking.block_binding !== void 0);
|
|
5596
|
+
}
|
|
5597
|
+
validateAndBindFinalBody(body) {
|
|
5598
|
+
const model = typeof body.model === "string" ? body.model : "";
|
|
5599
|
+
if (resolveClaudeCapability(model)?.thinkingBinding !== true) return;
|
|
5600
|
+
const reject = (option, remediation) => {
|
|
5601
|
+
throw new UnsupportedModelOptionError({ provider: this.name, model, option, remediation });
|
|
5602
|
+
};
|
|
5603
|
+
const toolChoice = body.tool_choice;
|
|
5604
|
+
if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
|
|
5605
|
+
reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
|
|
5606
|
+
}
|
|
5607
|
+
if (body.thinking !== void 0 && (!isRecord(body.thinking) || body.thinking.type !== "adaptive" || body.thinking.budget_tokens !== void 0)) {
|
|
5608
|
+
reject(
|
|
5609
|
+
"manual or disabled thinking",
|
|
5610
|
+
"Use thinking: { type: 'adaptive' } and output_config.effort."
|
|
5611
|
+
);
|
|
5612
|
+
}
|
|
5613
|
+
const outputConfig = body.output_config;
|
|
5614
|
+
if (outputConfig !== void 0 && (!isRecord(outputConfig) || outputConfig.effort !== void 0 && !["low", "medium", "high", "xhigh", "max"].includes(String(outputConfig.effort)))) {
|
|
5615
|
+
reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
|
|
5616
|
+
}
|
|
5617
|
+
if (body.temperature !== void 0 && body.temperature !== 1) {
|
|
5618
|
+
reject("temperature", "Omit temperature or use the default value 1.");
|
|
5619
|
+
}
|
|
5620
|
+
if (body.top_p !== void 0 && (typeof body.top_p !== "number" || body.top_p < 0.99 || body.top_p > 1)) {
|
|
5621
|
+
reject("top_p", "Omit top_p or use a value from 0.99 to 1.");
|
|
5622
|
+
}
|
|
5623
|
+
if (body.top_k !== void 0) {
|
|
5624
|
+
reject("top_k", "Omit top_k on this model.");
|
|
5625
|
+
}
|
|
5626
|
+
const replayed = hasReplayedThinking(body);
|
|
5627
|
+
if (!replayed) return;
|
|
5628
|
+
const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
|
|
5629
|
+
const binding = thinking.block_binding;
|
|
5630
|
+
if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
|
|
5631
|
+
reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
|
|
5632
|
+
}
|
|
5633
|
+
body.thinking = {
|
|
5634
|
+
...thinking,
|
|
5635
|
+
block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
|
|
5315
5636
|
};
|
|
5316
5637
|
}
|
|
5317
5638
|
/** Extract a human-readable message from an API error response body. */
|
|
@@ -5390,6 +5711,7 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5390
5711
|
if (options.providerOptions) {
|
|
5391
5712
|
Object.assign(body, options.providerOptions);
|
|
5392
5713
|
}
|
|
5714
|
+
this.validateAndBindFinalBody(body);
|
|
5393
5715
|
return body;
|
|
5394
5716
|
}
|
|
5395
5717
|
/**
|
|
@@ -5546,6 +5868,7 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5546
5868
|
}
|
|
5547
5869
|
}
|
|
5548
5870
|
const normalized = json.usage ? normalizeAnthropicUsage(json.usage) : void 0;
|
|
5871
|
+
const reasoningContextReset = normalizeThinkingDrops(json.input_transformations);
|
|
5549
5872
|
const effectiveModel = typeof json.model === "string" ? json.model : pricingContext.model;
|
|
5550
5873
|
if (hasFallbackBoundary) {
|
|
5551
5874
|
throw new Error(
|
|
@@ -5560,7 +5883,8 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5560
5883
|
usage: normalized?.usage,
|
|
5561
5884
|
cost,
|
|
5562
5885
|
costProvenance: tableEstimate(cost),
|
|
5563
|
-
providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary ? { anthropicThinkingBlocks: thinkingBlocks } : void 0
|
|
5886
|
+
providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary ? { anthropicThinkingBlocks: thinkingBlocks } : void 0,
|
|
5887
|
+
...reasoningContextReset ? { diagnostics: { reasoningContextReset } } : {}
|
|
5564
5888
|
};
|
|
5565
5889
|
}
|
|
5566
5890
|
// ---------------------------------------------------------------------------
|
|
@@ -5582,6 +5906,7 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5582
5906
|
let hasFallbackBoundary = false;
|
|
5583
5907
|
let hasFallbackIterationSignal = false;
|
|
5584
5908
|
let refused = false;
|
|
5909
|
+
let reasoningContextReset;
|
|
5585
5910
|
const finalizeUsage = () => {
|
|
5586
5911
|
const normalized = rawUsage ? normalizeAnthropicUsage(rawUsage) : void 0;
|
|
5587
5912
|
usage = normalized?.usage;
|
|
@@ -5594,7 +5919,8 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5594
5919
|
usage,
|
|
5595
5920
|
cost,
|
|
5596
5921
|
costProvenance: tableEstimate(cost),
|
|
5597
|
-
providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary && !hasFallbackIterationSignal ? { anthropicThinkingBlocks: thinkingBlocks } : void 0
|
|
5922
|
+
providerMetadata: thinkingBlocks.length > 0 && !hasFallbackBoundary && !hasFallbackIterationSignal ? { anthropicThinkingBlocks: thinkingBlocks } : void 0,
|
|
5923
|
+
...reasoningContextReset ? { diagnostics: { reasoningContextReset } } : {}
|
|
5598
5924
|
};
|
|
5599
5925
|
};
|
|
5600
5926
|
try {
|
|
@@ -5687,6 +6013,7 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5687
6013
|
rawUsage = mergeAnthropicUsage(rawUsage, event.message.usage);
|
|
5688
6014
|
}
|
|
5689
6015
|
if (typeof event.message?.model === "string") effectiveModel = event.message.model;
|
|
6016
|
+
reasoningContextReset = normalizeThinkingDrops(event.message?.input_transformations);
|
|
5690
6017
|
const messageFallback = hasFallbackIteration(event.message?.usage?.iterations);
|
|
5691
6018
|
if (isAnthropicResponseModifier(
|
|
5692
6019
|
"inference_geo",
|
|
@@ -5703,6 +6030,10 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
5703
6030
|
break;
|
|
5704
6031
|
}
|
|
5705
6032
|
case "message_delta": {
|
|
6033
|
+
const finalTransformations = event.input_transformations ?? event.delta?.input_transformations;
|
|
6034
|
+
if (finalTransformations !== void 0) {
|
|
6035
|
+
reasoningContextReset = normalizeThinkingDrops(finalTransformations);
|
|
6036
|
+
}
|
|
5706
6037
|
if (event.usage) {
|
|
5707
6038
|
rawUsage = mergeAnthropicUsage(rawUsage, event.usage);
|
|
5708
6039
|
finalizeUsage();
|
|
@@ -5931,7 +6262,31 @@ var GEMINI_PRICING = {
|
|
|
5931
6262
|
},
|
|
5932
6263
|
"gemini-3.8-flash": { input: 75e-8, cached: 75e-9, output: 375e-8 }
|
|
5933
6264
|
};
|
|
6265
|
+
var GEMINI_FLASH_SUCCESSOR_PRICING = {
|
|
6266
|
+
...GEMINI_PRICING,
|
|
6267
|
+
"gemini-3.6-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 },
|
|
6268
|
+
"gemini-3.7-flash": {
|
|
6269
|
+
input: 15e-7,
|
|
6270
|
+
cached: 15e-8,
|
|
6271
|
+
output: 75e-7,
|
|
6272
|
+
audioInput: 15e-7
|
|
6273
|
+
},
|
|
6274
|
+
"gemini-3.8-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 }
|
|
6275
|
+
};
|
|
6276
|
+
var GEMINI_FLASH_SUCCESSOR_START_MS = Date.UTC(2027, 0, 1);
|
|
6277
|
+
function geminiRatesAtDispatch(at) {
|
|
6278
|
+
return at < GEMINI_FLASH_SUCCESSOR_START_MS ? GEMINI_PRICING : GEMINI_FLASH_SUCCESSOR_PRICING;
|
|
6279
|
+
}
|
|
5934
6280
|
var CANONICAL_GEMINI_BASE_URL = GEMINI_DEFAULT_BASE_URL;
|
|
6281
|
+
function geminiPricingTimingObserver(context, recorder) {
|
|
6282
|
+
return {
|
|
6283
|
+
...recorder.observer,
|
|
6284
|
+
onDispatch: (attempt, at) => {
|
|
6285
|
+
context.rates = geminiRatesAtDispatch(at);
|
|
6286
|
+
recorder.observer.onDispatch?.(attempt, at);
|
|
6287
|
+
}
|
|
6288
|
+
};
|
|
6289
|
+
}
|
|
5935
6290
|
function isValidTokenCount2(value) {
|
|
5936
6291
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
5937
6292
|
}
|
|
@@ -6012,8 +6367,8 @@ function geminiInteractionErrorStatus(code) {
|
|
|
6012
6367
|
function isEligibleGeminiPricing(context, hasDefinitiveStandardResponseTier, hasInvalidResponseTier) {
|
|
6013
6368
|
return context.eligibleRequest && isStandardGeminiRequestTier(context.serviceTier) && hasDefinitiveStandardResponseTier && !hasInvalidResponseTier;
|
|
6014
6369
|
}
|
|
6015
|
-
function estimateGeminiCost(model, usage) {
|
|
6016
|
-
const pricing =
|
|
6370
|
+
function estimateGeminiCost(model, usage, rates) {
|
|
6371
|
+
const pricing = rates && Object.hasOwn(rates, model) ? rates[model] : void 0;
|
|
6017
6372
|
const cached = usage.cachedTokens ?? 0;
|
|
6018
6373
|
if (!pricing || !isValidTokenCount2(usage.inputTokens) || !isValidTokenCount2(usage.outputTokens) || !isValidTokenCount2(cached) || cached > usage.inputTokens) {
|
|
6019
6374
|
return void 0;
|
|
@@ -6341,7 +6696,7 @@ var GeminiProvider = class {
|
|
|
6341
6696
|
{
|
|
6342
6697
|
governor: this.governorFor(pricingContext.model),
|
|
6343
6698
|
provider: this.name,
|
|
6344
|
-
timing: recorder
|
|
6699
|
+
timing: geminiPricingTimingObserver(pricingContext, recorder),
|
|
6345
6700
|
admission: options.dispatchAdmission
|
|
6346
6701
|
}
|
|
6347
6702
|
);
|
|
@@ -6384,7 +6739,7 @@ var GeminiProvider = class {
|
|
|
6384
6739
|
{
|
|
6385
6740
|
governor: this.governorFor(pricingContext.model),
|
|
6386
6741
|
provider: this.name,
|
|
6387
|
-
timing: recorder
|
|
6742
|
+
timing: geminiPricingTimingObserver(pricingContext, recorder),
|
|
6388
6743
|
admission: options.dispatchAdmission
|
|
6389
6744
|
}
|
|
6390
6745
|
);
|
|
@@ -6422,7 +6777,7 @@ var GeminiProvider = class {
|
|
|
6422
6777
|
{
|
|
6423
6778
|
governor: this.governorFor(pricingContext.model),
|
|
6424
6779
|
provider: this.name,
|
|
6425
|
-
timing: recorder
|
|
6780
|
+
timing: geminiPricingTimingObserver(pricingContext, recorder),
|
|
6426
6781
|
admission: options.dispatchAdmission
|
|
6427
6782
|
}
|
|
6428
6783
|
);
|
|
@@ -6458,7 +6813,7 @@ var GeminiProvider = class {
|
|
|
6458
6813
|
{
|
|
6459
6814
|
governor: this.governorFor(pricingContext.model),
|
|
6460
6815
|
provider: this.name,
|
|
6461
|
-
timing: recorder
|
|
6816
|
+
timing: geminiPricingTimingObserver(pricingContext, recorder),
|
|
6462
6817
|
admission: options.dispatchAdmission
|
|
6463
6818
|
}
|
|
6464
6819
|
);
|
|
@@ -6677,7 +7032,7 @@ var GeminiProvider = class {
|
|
|
6677
7032
|
)) {
|
|
6678
7033
|
return void 0;
|
|
6679
7034
|
}
|
|
6680
|
-
return estimateGeminiCost(effectiveModel, normalized.pricingUsage);
|
|
7035
|
+
return estimateGeminiCost(effectiveModel, normalized.pricingUsage, pricingContext.rates);
|
|
6681
7036
|
}
|
|
6682
7037
|
/**
|
|
6683
7038
|
* Whether every model-produced step is text. A non-text reply part (image,
|
|
@@ -7262,7 +7617,7 @@ var GeminiProvider = class {
|
|
|
7262
7617
|
pricingContext,
|
|
7263
7618
|
isDefinitiveStandardGeminiResponseTier(json.usageMetadata?.serviceTier),
|
|
7264
7619
|
json.usageMetadata?.serviceTier !== void 0 && !isDefinitiveStandardGeminiResponseTier(json.usageMetadata.serviceTier)
|
|
7265
|
-
) ? estimateGeminiCost(effectiveModel, normalized.pricingUsage) : void 0;
|
|
7620
|
+
) ? estimateGeminiCost(effectiveModel, normalized.pricingUsage, pricingContext.rates) : void 0;
|
|
7266
7621
|
const rawParts = candidate?.content?.parts;
|
|
7267
7622
|
const providerMetadata = rawParts ? { geminiParts: rawParts } : void 0;
|
|
7268
7623
|
return {
|
|
@@ -7353,7 +7708,7 @@ var GeminiProvider = class {
|
|
|
7353
7708
|
pricingContext,
|
|
7354
7709
|
hasDefinitiveStandardResponseTier,
|
|
7355
7710
|
hasInvalidResponseTier
|
|
7356
|
-
) ? estimateGeminiCost(effectiveModel, normalizedUsage.pricingUsage) : void 0;
|
|
7711
|
+
) ? estimateGeminiCost(effectiveModel, normalizedUsage.pricingUsage, pricingContext.rates) : void 0;
|
|
7357
7712
|
yield {
|
|
7358
7713
|
type: "done",
|
|
7359
7714
|
usage: normalizedUsage?.usage,
|
|
@@ -9002,7 +9357,7 @@ var TranscriptionProviderRegistry = class {
|
|
|
9002
9357
|
};
|
|
9003
9358
|
|
|
9004
9359
|
// src/context.ts
|
|
9005
|
-
import { AsyncLocalStorage as
|
|
9360
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
9006
9361
|
import { randomUUID } from "crypto";
|
|
9007
9362
|
import { z, ZodError as ZodError2 } from "zod";
|
|
9008
9363
|
|
|
@@ -9266,6 +9621,95 @@ function sessionHistoryForAsk(history, normalizedInput) {
|
|
|
9266
9621
|
return snapshot;
|
|
9267
9622
|
}
|
|
9268
9623
|
|
|
9624
|
+
// src/compaction.ts
|
|
9625
|
+
import { createHash } from "crypto";
|
|
9626
|
+
var SUMMARY_SYSTEM_PROMPT = "Summarize the following conversation concisely, preserving key facts, decisions, and context needed for continuing the conversation.";
|
|
9627
|
+
var SUMMARY_MAX_TOKENS = 1024;
|
|
9628
|
+
function buildSummaryPrompt(messages, previousSummary) {
|
|
9629
|
+
return [
|
|
9630
|
+
...previousSummary ? [`Previous conversation summary: ${previousSummary}`] : [],
|
|
9631
|
+
...messages.map((m) => `${m.role}: ${summarizeModelInput(m.content)}`)
|
|
9632
|
+
].join("\n");
|
|
9633
|
+
}
|
|
9634
|
+
function requestSummary(provider, options) {
|
|
9635
|
+
return provider.chat(
|
|
9636
|
+
[
|
|
9637
|
+
{ role: "system", content: SUMMARY_SYSTEM_PROMPT },
|
|
9638
|
+
{ role: "user", content: options.prompt }
|
|
9639
|
+
],
|
|
9640
|
+
{
|
|
9641
|
+
model: options.model,
|
|
9642
|
+
maxTokens: SUMMARY_MAX_TOKENS,
|
|
9643
|
+
...options.signal ? { signal: options.signal } : {}
|
|
9644
|
+
}
|
|
9645
|
+
);
|
|
9646
|
+
}
|
|
9647
|
+
function summaryContextMessage(summary) {
|
|
9648
|
+
return {
|
|
9649
|
+
role: "system",
|
|
9650
|
+
origin: "runtime",
|
|
9651
|
+
content: `Summary of earlier conversation:
|
|
9652
|
+
${summary}`
|
|
9653
|
+
};
|
|
9654
|
+
}
|
|
9655
|
+
function withoutAnthropicThinking(message) {
|
|
9656
|
+
const metadata = message.providerMetadata;
|
|
9657
|
+
if (!metadata || !Object.hasOwn(metadata, "anthropicThinkingBlocks")) return message;
|
|
9658
|
+
const retainedMetadata = { ...metadata };
|
|
9659
|
+
delete retainedMetadata.anthropicThinkingBlocks;
|
|
9660
|
+
return {
|
|
9661
|
+
...message,
|
|
9662
|
+
...Object.keys(retainedMetadata).length > 0 ? { providerMetadata: retainedMetadata } : { providerMetadata: void 0 }
|
|
9663
|
+
};
|
|
9664
|
+
}
|
|
9665
|
+
function anthropicThinkingBlockCount(message) {
|
|
9666
|
+
const blocks = message.providerMetadata?.anthropicThinkingBlocks;
|
|
9667
|
+
if (!Array.isArray(blocks)) return 0;
|
|
9668
|
+
return blocks.filter(
|
|
9669
|
+
(block) => block !== null && typeof block === "object" && (block.type === "thinking" || block.type === "redacted_thinking")
|
|
9670
|
+
).length;
|
|
9671
|
+
}
|
|
9672
|
+
function askSummaryMetaKey(agentName) {
|
|
9673
|
+
return `askSummary:${agentName}`;
|
|
9674
|
+
}
|
|
9675
|
+
function isCount(value) {
|
|
9676
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
9677
|
+
}
|
|
9678
|
+
function parseAskSummaryRecord(value) {
|
|
9679
|
+
if (!value || typeof value !== "object") return void 0;
|
|
9680
|
+
const record = value;
|
|
9681
|
+
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") {
|
|
9682
|
+
return void 0;
|
|
9683
|
+
}
|
|
9684
|
+
return {
|
|
9685
|
+
summary: record.summary,
|
|
9686
|
+
coveredCount: record.coveredCount,
|
|
9687
|
+
prefixHash: record.prefixHash,
|
|
9688
|
+
...record.sourceSummary !== void 0 ? { sourceSummary: record.sourceSummary } : {},
|
|
9689
|
+
summaryModelUri: record.summaryModelUri,
|
|
9690
|
+
invalidatedThinkingThrough: record.invalidatedThinkingThrough
|
|
9691
|
+
};
|
|
9692
|
+
}
|
|
9693
|
+
function isPlainObject(value) {
|
|
9694
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
9695
|
+
const proto = Object.getPrototypeOf(value);
|
|
9696
|
+
return proto === Object.prototype || proto === null;
|
|
9697
|
+
}
|
|
9698
|
+
function summaryPrefixHash(history, coveredCount) {
|
|
9699
|
+
let canonical;
|
|
9700
|
+
try {
|
|
9701
|
+
canonical = JSON.stringify(
|
|
9702
|
+
history.slice(0, coveredCount),
|
|
9703
|
+
(_key, value) => isPlainObject(value) ? Object.fromEntries(
|
|
9704
|
+
Object.keys(value).sort().map((key) => [key, value[key]])
|
|
9705
|
+
) : value
|
|
9706
|
+
);
|
|
9707
|
+
} catch {
|
|
9708
|
+
return void 0;
|
|
9709
|
+
}
|
|
9710
|
+
return createHash("sha256").update(canonical).digest("hex");
|
|
9711
|
+
}
|
|
9712
|
+
|
|
9269
9713
|
// src/partial-json.ts
|
|
9270
9714
|
var MAX_DEPTH = 256;
|
|
9271
9715
|
function parsePartialJson(input) {
|
|
@@ -10902,9 +11346,9 @@ var LEGACY_REDACTION_RULES = {
|
|
|
10902
11346
|
// which is user content or PII (field paths are schema-shape, preserved like
|
|
10903
11347
|
// `string_delta.path`). Passthrough, as an explicit reviewed decision.
|
|
10904
11348
|
schema_diagnostic: passthrough,
|
|
10905
|
-
// `provider_diagnostic` carries only provider
|
|
10906
|
-
//
|
|
10907
|
-
//
|
|
11349
|
+
// `provider_diagnostic` carries only provider/model metadata, effort levels,
|
|
11350
|
+
// and bounded dropped-thinking reason counts. Raw transformation paths and
|
|
11351
|
+
// signed thinking never enter this event. Passthrough is reviewed here.
|
|
10908
11352
|
provider_diagnostic: passthrough,
|
|
10909
11353
|
log: (e) => {
|
|
10910
11354
|
if (!e.data || typeof e.data !== "object" || Array.isArray(e.data)) return e;
|
|
@@ -12534,9 +12978,8 @@ function recordToolSpanOutcome(span, outcome) {
|
|
|
12534
12978
|
}
|
|
12535
12979
|
|
|
12536
12980
|
// src/context.ts
|
|
12537
|
-
var signalStorage = new
|
|
12538
|
-
var hardSignalStorage = new
|
|
12539
|
-
var timeoutTrackerStorage = new AsyncLocalStorage2();
|
|
12981
|
+
var signalStorage = new AsyncLocalStorage3();
|
|
12982
|
+
var hardSignalStorage = new AsyncLocalStorage3();
|
|
12540
12983
|
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
12541
12984
|
function composeAbortSignals(...signals) {
|
|
12542
12985
|
const active = signals.filter((signal) => signal !== void 0);
|
|
@@ -12568,9 +13011,6 @@ function raceWithAbortSignal(promise, signal) {
|
|
|
12568
13011
|
);
|
|
12569
13012
|
});
|
|
12570
13013
|
}
|
|
12571
|
-
function pausedHumanWaitMs(tracker, now = Date.now()) {
|
|
12572
|
-
return tracker.humanWaitMs + (tracker.activeHumanWaits > 0 && tracker.humanWaitStartedAt !== void 0 ? now - tracker.humanWaitStartedAt : 0);
|
|
12573
|
-
}
|
|
12574
13014
|
var DEFAULT_BRANCH_DRAIN_TIMEOUT_MS = 5e3;
|
|
12575
13015
|
function resolveBranchDrainTimeoutMs(value) {
|
|
12576
13016
|
const resolved = value === void 0 ? DEFAULT_BRANCH_DRAIN_TIMEOUT_MS : value;
|
|
@@ -12641,7 +13081,7 @@ function parseHumanDecision(value) {
|
|
|
12641
13081
|
}
|
|
12642
13082
|
return invalid3();
|
|
12643
13083
|
}
|
|
12644
|
-
var askStorage = new
|
|
13084
|
+
var askStorage = new AsyncLocalStorage3();
|
|
12645
13085
|
var inlineSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
12646
13086
|
function zodToJsonSchema(schema) {
|
|
12647
13087
|
const cached = inlineSchemaCache.get(schema);
|
|
@@ -12913,7 +13353,14 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
12913
13353
|
* suppresses late branch events after bounded finalization. */
|
|
12914
13354
|
workflowLifecycleState;
|
|
12915
13355
|
signal;
|
|
12916
|
-
|
|
13356
|
+
/** Durable summary of messages removed by Session.history.maxMessages. */
|
|
13357
|
+
sessionSummary;
|
|
13358
|
+
/** Per-agent `maxContext` summaries, keyed by agent name. `null` records a
|
|
13359
|
+
* store lookup that found nothing. Mirrored to session metadata
|
|
13360
|
+
* (`askSummary:<agent>`) when this execution belongs to a session, so a
|
|
13361
|
+
* later execution can reuse the same exact-prefix boundary. Never the
|
|
13362
|
+
* durable `sessionSummary`. */
|
|
13363
|
+
askSummaries = /* @__PURE__ */ new Map();
|
|
12917
13364
|
/** Consecutive provider calls with promptCache on that wrote to the cache
|
|
12918
13365
|
* without reading from it (prefix changes per call), and consecutive calls
|
|
12919
13366
|
* with no cache activity at all (prefix below the model's minimum, which
|
|
@@ -13089,7 +13536,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
13089
13536
|
endEmitted: false
|
|
13090
13537
|
};
|
|
13091
13538
|
if (init.metadata?.summaryCache) {
|
|
13092
|
-
this.
|
|
13539
|
+
this.sessionSummary = init.metadata.summaryCache;
|
|
13093
13540
|
}
|
|
13094
13541
|
}
|
|
13095
13542
|
/**
|
|
@@ -13578,10 +14025,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
13578
14025
|
return hardAskSignal ? hardSignalStorage.run(hardAskSignal, runWithAskSignal) : runWithAskSignal();
|
|
13579
14026
|
}
|
|
13580
14027
|
async executeAgentCall(agent2, input, options, handoffMessages, usageCapture, sessionHistory = normalizeSessionHistory(this.sessionHistory)) {
|
|
13581
|
-
|
|
13582
|
-
const enclosing = timeoutTrackerStorage.getStore() ?? [];
|
|
13583
|
-
return timeoutTrackerStorage.run(
|
|
13584
|
-
[...enclosing, tracker],
|
|
14028
|
+
return runWithAskClock(
|
|
13585
14029
|
() => this.executeAgentCallImpl(
|
|
13586
14030
|
agent2,
|
|
13587
14031
|
input,
|
|
@@ -13717,6 +14161,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
13717
14161
|
if (systemPrompt) {
|
|
13718
14162
|
messages.push({ role: "system", content: systemPrompt });
|
|
13719
14163
|
}
|
|
14164
|
+
const cachedSummaryMessage = this.sessionSummary ? summaryContextMessage(this.sessionSummary) : void 0;
|
|
13720
14165
|
const maxContext = agent2._config.maxContext;
|
|
13721
14166
|
if (maxContext && sessionHistory.length > 0) {
|
|
13722
14167
|
const reserveTokens = this.config.contextManagement?.reserveTokens ?? 2e3;
|
|
@@ -13741,22 +14186,44 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
13741
14186
|
}
|
|
13742
14187
|
});
|
|
13743
14188
|
}
|
|
13744
|
-
|
|
13745
|
-
|
|
14189
|
+
const summaryTokens = cachedSummaryMessage ? estimateMessagesTokens([cachedSummaryMessage]).tokens : 0;
|
|
14190
|
+
if (historyEstimate.tokens + summaryTokens > availableForHistory) {
|
|
14191
|
+
const projection = await this.summarizeHistory(
|
|
14192
|
+
agent2._name,
|
|
14193
|
+
modelUri,
|
|
13746
14194
|
provider,
|
|
13747
14195
|
model,
|
|
13748
14196
|
sessionHistory,
|
|
13749
14197
|
availableForHistory
|
|
13750
14198
|
);
|
|
13751
|
-
|
|
14199
|
+
if (this.budgetContext?.exceeded && this.budgetContext.policy !== "warn") {
|
|
14200
|
+
const { limit, totalCost: spent, policy } = this.budgetContext;
|
|
14201
|
+
throw new BudgetExceededError(limit, spent, policy);
|
|
14202
|
+
}
|
|
14203
|
+
if (projection.removedThinkingBlocks > 0) {
|
|
14204
|
+
this.emitEvent({
|
|
14205
|
+
type: "provider_diagnostic",
|
|
14206
|
+
agent: agent2._name,
|
|
14207
|
+
data: {
|
|
14208
|
+
kind: "reasoning_context_reset",
|
|
14209
|
+
...provider.name ? { provider: provider.name } : {},
|
|
14210
|
+
model: typeof providerOptions?.model === "string" ? providerOptions.model : model,
|
|
14211
|
+
droppedBlocks: projection.removedThinkingBlocks,
|
|
14212
|
+
reasons: { client_prefix_rewrite: projection.removedThinkingBlocks }
|
|
14213
|
+
}
|
|
14214
|
+
});
|
|
14215
|
+
}
|
|
14216
|
+
for (const msg of projection.messages) {
|
|
13752
14217
|
messages.push(msg);
|
|
13753
14218
|
}
|
|
13754
14219
|
} else {
|
|
14220
|
+
if (cachedSummaryMessage) messages.push(cachedSummaryMessage);
|
|
13755
14221
|
for (const msg of sessionHistory) {
|
|
13756
14222
|
messages.push(msg);
|
|
13757
14223
|
}
|
|
13758
14224
|
}
|
|
13759
14225
|
} else {
|
|
14226
|
+
if (cachedSummaryMessage) messages.push(cachedSummaryMessage);
|
|
13760
14227
|
for (const msg of sessionHistory) {
|
|
13761
14228
|
messages.push(msg);
|
|
13762
14229
|
}
|
|
@@ -13856,7 +14323,8 @@ ${appendedSchemaText}`;
|
|
|
13856
14323
|
);
|
|
13857
14324
|
}
|
|
13858
14325
|
const startTime = Date.now();
|
|
13859
|
-
const
|
|
14326
|
+
const askClock = currentAskClock();
|
|
14327
|
+
const pausedAtStartMs = askClock ? pausedAskClockMs(askClock, startTime) : 0;
|
|
13860
14328
|
const timingTotals = { turns: 0, queuedMs: 0, retryMs: 0, wireMs: 0 };
|
|
13861
14329
|
const currentMessages = [...messages];
|
|
13862
14330
|
let turns = 0;
|
|
@@ -13873,13 +14341,16 @@ ${appendedSchemaText}`;
|
|
|
13873
14341
|
while (turns < maxTurns) {
|
|
13874
14342
|
this.currentSignal?.throwIfAborted();
|
|
13875
14343
|
const now = Date.now();
|
|
13876
|
-
const elapsedMs = now - startTime
|
|
13877
|
-
|
|
14344
|
+
const elapsedMs = now - startTime;
|
|
14345
|
+
const pausedMs = askClock ? Math.max(0, pausedAskClockMs(askClock, now) - pausedAtStartMs) : 0;
|
|
14346
|
+
const chargedMs = Math.max(0, elapsedMs - Math.min(pausedMs, Math.max(0, elapsedMs)));
|
|
14347
|
+
if (chargedMs > timeoutMs) {
|
|
13878
14348
|
throw new TimeoutError(
|
|
13879
14349
|
"ctx.ask()",
|
|
13880
14350
|
timeoutMs,
|
|
13881
14351
|
timingTotals.turns > 0 ? {
|
|
13882
14352
|
elapsedMs,
|
|
14353
|
+
chargedMs,
|
|
13883
14354
|
queuedMs: timingTotals.queuedMs,
|
|
13884
14355
|
retryMs: timingTotals.retryMs,
|
|
13885
14356
|
wireMs: timingTotals.wireMs,
|
|
@@ -14126,6 +14597,7 @@ ${appendedSchemaText}`;
|
|
|
14126
14597
|
usage: chunk.usage,
|
|
14127
14598
|
cost: chunk.cost,
|
|
14128
14599
|
providerMetadata: chunk.providerMetadata,
|
|
14600
|
+
diagnostics: chunk.diagnostics,
|
|
14129
14601
|
timing: chunk.timing
|
|
14130
14602
|
};
|
|
14131
14603
|
}
|
|
@@ -14243,6 +14715,34 @@ ${appendedSchemaText}`;
|
|
|
14243
14715
|
timingTotals.retryMs += response.timing.retryMs;
|
|
14244
14716
|
timingTotals.wireMs += response.timing.wireMs;
|
|
14245
14717
|
}
|
|
14718
|
+
const reasoningReset = response.diagnostics?.reasoningContextReset;
|
|
14719
|
+
if (reasoningReset && Number.isSafeInteger(reasoningReset.droppedBlocks) && reasoningReset.droppedBlocks > 0) {
|
|
14720
|
+
const reasons = {};
|
|
14721
|
+
for (const reason of [
|
|
14722
|
+
"prefix_binding_mismatch",
|
|
14723
|
+
"model_binding_mismatch",
|
|
14724
|
+
"organization_binding_mismatch",
|
|
14725
|
+
"end_user_binding_mismatch",
|
|
14726
|
+
"client_prefix_rewrite",
|
|
14727
|
+
"other"
|
|
14728
|
+
]) {
|
|
14729
|
+
const count = reasoningReset.reasons?.[reason];
|
|
14730
|
+
if (typeof count === "number" && Number.isSafeInteger(count) && count > 0) {
|
|
14731
|
+
reasons[reason] = count;
|
|
14732
|
+
}
|
|
14733
|
+
}
|
|
14734
|
+
this.emitEvent({
|
|
14735
|
+
type: "provider_diagnostic",
|
|
14736
|
+
agent: agent2._name,
|
|
14737
|
+
data: {
|
|
14738
|
+
kind: "reasoning_context_reset",
|
|
14739
|
+
...provider.name ? { provider: provider.name } : {},
|
|
14740
|
+
model: typeof providerOptions?.model === "string" ? providerOptions.model : model,
|
|
14741
|
+
droppedBlocks: reasoningReset.droppedBlocks,
|
|
14742
|
+
reasons
|
|
14743
|
+
}
|
|
14744
|
+
});
|
|
14745
|
+
}
|
|
14246
14746
|
this.emitEvent({
|
|
14247
14747
|
type: "agent_call_end",
|
|
14248
14748
|
agent: agent2._name,
|
|
@@ -14985,31 +15485,65 @@ ${appendedSchemaText}`;
|
|
|
14985
15485
|
}
|
|
14986
15486
|
return defs;
|
|
14987
15487
|
}
|
|
15488
|
+
/** Session id for session-scoped ask-summary persistence, when this
|
|
15489
|
+
* execution belongs to a session and has a store to persist into. */
|
|
15490
|
+
askSummarySessionId() {
|
|
15491
|
+
const sessionId = this.metadata?.sessionId;
|
|
15492
|
+
if (this.metadata?.sessionPersist === false) return void 0;
|
|
15493
|
+
return this.stateStore && typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
|
|
15494
|
+
}
|
|
15495
|
+
/** This agent's ask summary: the in-memory copy first, else the session's
|
|
15496
|
+
* persisted record (read once per execution). */
|
|
15497
|
+
async loadAskSummary(agentName) {
|
|
15498
|
+
if (this.askSummaries.has(agentName)) return this.askSummaries.get(agentName) ?? void 0;
|
|
15499
|
+
const sessionId = this.askSummarySessionId();
|
|
15500
|
+
const stored = sessionId ? parseAskSummaryRecord(
|
|
15501
|
+
await this.stateStore.getSessionMeta(sessionId, askSummaryMetaKey(agentName))
|
|
15502
|
+
) : void 0;
|
|
15503
|
+
this.askSummaries.set(agentName, stored ?? null);
|
|
15504
|
+
return stored;
|
|
15505
|
+
}
|
|
15506
|
+
async saveAskSummary(agentName, record) {
|
|
15507
|
+
this.askSummaries.set(agentName, record);
|
|
15508
|
+
const sessionId = this.askSummarySessionId();
|
|
15509
|
+
if (!sessionId) return;
|
|
15510
|
+
const key = askSummaryMetaKey(agentName);
|
|
15511
|
+
try {
|
|
15512
|
+
await this.stateStore.saveSessionMeta(sessionId, key, record);
|
|
15513
|
+
} catch (error) {
|
|
15514
|
+
this.emitEvent({
|
|
15515
|
+
type: "log",
|
|
15516
|
+
agent: agentName,
|
|
15517
|
+
data: {
|
|
15518
|
+
warning: `Could not persist ask summary '${key}' for session '${sessionId}'; later executions will regenerate it. ` + (error instanceof Error ? error.message : String(error))
|
|
15519
|
+
}
|
|
15520
|
+
});
|
|
15521
|
+
}
|
|
15522
|
+
}
|
|
14988
15523
|
/**
|
|
14989
|
-
*
|
|
14990
|
-
*
|
|
15524
|
+
* Project `history` into `availableTokens` for one agent's request: a summary
|
|
15525
|
+
* of an exact covered prefix followed by every later message. Reuses the
|
|
15526
|
+
* agent's cached boundary (in memory or persisted for the session) while the
|
|
15527
|
+
* covered prefix, durable session summary, and summary model are unchanged
|
|
15528
|
+
* and the whole tail fits; otherwise generates a new summary. Also reports how
|
|
15529
|
+
* many Anthropic thinking blocks the projection removed from carried turns.
|
|
14991
15530
|
*/
|
|
14992
|
-
async summarizeHistory(provider, model, history, availableTokens) {
|
|
14993
|
-
|
|
14994
|
-
|
|
14995
|
-
|
|
14996
|
-
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
|
|
15001
|
-
|
|
15002
|
-
|
|
15003
|
-
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
splitIdx2 = i;
|
|
15009
|
-
}
|
|
15010
|
-
splitIdx2 = nextUserTurn(history, splitIdx2) ?? history.length;
|
|
15011
|
-
if (splitIdx2 < history.length) {
|
|
15012
|
-
return [summaryMsg2, ...history.slice(splitIdx2)];
|
|
15531
|
+
async summarizeHistory(agentName, modelUri, provider, model, history, availableTokens) {
|
|
15532
|
+
const summaryModelUri = this.config.contextManagement?.summaryModel ?? modelUri;
|
|
15533
|
+
const cache = await this.loadAskSummary(agentName);
|
|
15534
|
+
if (cache && cache.sourceSummary === this.sessionSummary && cache.summaryModelUri === summaryModelUri && cache.coveredCount <= history.length && cache.prefixHash === summaryPrefixHash(history, cache.coveredCount)) {
|
|
15535
|
+
const summaryMsg = summaryContextMessage(cache.summary);
|
|
15536
|
+
const summaryTokens = estimateTokens(summarizeModelInput(summaryMsg.content)) + 4;
|
|
15537
|
+
const tail2 = history.slice(cache.coveredCount);
|
|
15538
|
+
const tailTokens = estimateMessagesTokens(tail2).tokens;
|
|
15539
|
+
if (summaryTokens + tailTokens <= availableTokens && (tail2.length === 0 || tail2[0].role === "user")) {
|
|
15540
|
+
let removedThinkingBlocks = 0;
|
|
15541
|
+
const projected = tail2.map((message, index) => {
|
|
15542
|
+
if (cache.coveredCount + index >= cache.invalidatedThinkingThrough) return message;
|
|
15543
|
+
removedThinkingBlocks += anthropicThinkingBlockCount(message);
|
|
15544
|
+
return withoutAnthropicThinking(message);
|
|
15545
|
+
});
|
|
15546
|
+
return { messages: [summaryMsg, ...projected], removedThinkingBlocks };
|
|
15013
15547
|
}
|
|
15014
15548
|
}
|
|
15015
15549
|
let recentTokens = 0;
|
|
@@ -15034,42 +15568,103 @@ ${this.summaryCache}`
|
|
|
15034
15568
|
} else {
|
|
15035
15569
|
splitIdx = history.length;
|
|
15036
15570
|
}
|
|
15037
|
-
if (splitIdx === 0)
|
|
15571
|
+
if (splitIdx === 0 && this.sessionSummary) splitIdx = history.length;
|
|
15572
|
+
if (splitIdx === 0) return { messages: history, removedThinkingBlocks: 0 };
|
|
15038
15573
|
const oldMessages = history.slice(0, splitIdx);
|
|
15039
|
-
const
|
|
15574
|
+
const configuredSummaryModelUri = this.config.contextManagement?.summaryModel;
|
|
15040
15575
|
let summaryProvider;
|
|
15041
15576
|
let summaryModel;
|
|
15042
|
-
if (
|
|
15043
|
-
const resolved = this.resolveProviderUri(
|
|
15577
|
+
if (configuredSummaryModelUri) {
|
|
15578
|
+
const resolved = this.resolveProviderUri(configuredSummaryModelUri);
|
|
15044
15579
|
summaryProvider = resolved.provider;
|
|
15045
15580
|
summaryModel = resolved.model;
|
|
15046
15581
|
} else {
|
|
15047
15582
|
summaryProvider = provider;
|
|
15048
15583
|
summaryModel = model;
|
|
15049
15584
|
}
|
|
15050
|
-
const
|
|
15051
|
-
const
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15585
|
+
const summaryPrompt = buildSummaryPrompt(oldMessages, this.sessionSummary);
|
|
15586
|
+
const summaryStart = Date.now();
|
|
15587
|
+
this.emitEvent({
|
|
15588
|
+
type: "agent_call_start",
|
|
15589
|
+
agent: agentName,
|
|
15590
|
+
model: summaryModelUri,
|
|
15591
|
+
turn: 0,
|
|
15592
|
+
data: {
|
|
15593
|
+
purpose: "summary",
|
|
15594
|
+
prompt: summaryPrompt,
|
|
15595
|
+
system: SUMMARY_SYSTEM_PROMPT,
|
|
15596
|
+
params: { maxTokens: SUMMARY_MAX_TOKENS },
|
|
15597
|
+
turn: 0
|
|
15598
|
+
}
|
|
15599
|
+
});
|
|
15600
|
+
let summaryResponse;
|
|
15601
|
+
try {
|
|
15602
|
+
this.currentSignal?.throwIfAborted();
|
|
15603
|
+
summaryResponse = await requestSummary(summaryProvider, {
|
|
15604
|
+
model: summaryModel,
|
|
15605
|
+
prompt: summaryPrompt,
|
|
15606
|
+
signal: this.currentSignal
|
|
15607
|
+
});
|
|
15608
|
+
} catch (error) {
|
|
15609
|
+
const providerError = error instanceof ProviderError ? error : void 0;
|
|
15610
|
+
this.emitEvent({
|
|
15611
|
+
type: "agent_call_end",
|
|
15612
|
+
agent: agentName,
|
|
15613
|
+
model: summaryModelUri,
|
|
15614
|
+
duration: Date.now() - summaryStart,
|
|
15615
|
+
...providerError?.timing ? { timing: providerError.timing } : {},
|
|
15616
|
+
data: {
|
|
15617
|
+
purpose: "summary",
|
|
15618
|
+
response: "",
|
|
15619
|
+
turn: 0,
|
|
15620
|
+
// Provider errors may echo the summarized history, so the event
|
|
15621
|
+
// uses a fixed projection even when trace redaction is disabled.
|
|
15622
|
+
error: "Context-management summary call failed",
|
|
15623
|
+
...providerError ? { status: providerError.status, retryable: providerError.retryable } : {}
|
|
15624
|
+
}
|
|
15625
|
+
});
|
|
15626
|
+
throw error;
|
|
15627
|
+
}
|
|
15628
|
+
if (isUsableCost2(summaryResponse.cost)) this._accumulateBudgetCost(summaryResponse.cost);
|
|
15629
|
+
this.emitEvent({
|
|
15630
|
+
type: "agent_call_end",
|
|
15631
|
+
agent: agentName,
|
|
15632
|
+
model: summaryModelUri,
|
|
15633
|
+
cost: summaryResponse.cost,
|
|
15634
|
+
...!isUsableCost2(summaryResponse.cost) ? { unpriced: true } : {},
|
|
15635
|
+
tokens: summaryResponse.usage ? {
|
|
15636
|
+
input: summaryResponse.usage.prompt_tokens,
|
|
15637
|
+
output: summaryResponse.usage.completion_tokens,
|
|
15638
|
+
reasoning: summaryResponse.usage.reasoning_tokens,
|
|
15639
|
+
cached: summaryResponse.usage.cached_tokens,
|
|
15640
|
+
cacheWrite: summaryResponse.usage.cache_write_tokens
|
|
15641
|
+
} : void 0,
|
|
15642
|
+
duration: Date.now() - summaryStart,
|
|
15643
|
+
...summaryResponse.timing ? { timing: summaryResponse.timing } : {},
|
|
15644
|
+
data: { purpose: "summary", response: summaryResponse.content, turn: 0 }
|
|
15645
|
+
});
|
|
15646
|
+
const prefixHash = summaryPrefixHash(history, splitIdx);
|
|
15647
|
+
if (prefixHash) {
|
|
15648
|
+
await this.saveAskSummary(agentName, {
|
|
15649
|
+
summary: summaryResponse.content,
|
|
15650
|
+
coveredCount: splitIdx,
|
|
15651
|
+
prefixHash,
|
|
15652
|
+
...this.sessionSummary !== void 0 ? { sourceSummary: this.sessionSummary } : {},
|
|
15653
|
+
summaryModelUri,
|
|
15654
|
+
invalidatedThinkingThrough: history.length
|
|
15655
|
+
});
|
|
15656
|
+
}
|
|
15657
|
+
const tail = history.slice(splitIdx);
|
|
15658
|
+
return {
|
|
15659
|
+
messages: [
|
|
15660
|
+
summaryContextMessage(summaryResponse.content),
|
|
15661
|
+
...tail.map(withoutAnthropicThinking)
|
|
15058
15662
|
],
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
if (sessionId && this.stateStore) {
|
|
15064
|
-
await this.stateStore.saveSessionMeta(sessionId, "summaryCache", this.summaryCache);
|
|
15065
|
-
}
|
|
15066
|
-
const summaryMsg = {
|
|
15067
|
-
role: "system",
|
|
15068
|
-
origin: "runtime",
|
|
15069
|
-
content: `Summary of earlier conversation:
|
|
15070
|
-
${summaryResponse.content}`
|
|
15663
|
+
removedThinkingBlocks: tail.reduce(
|
|
15664
|
+
(count, message) => count + anthropicThinkingBlockCount(message),
|
|
15665
|
+
0
|
|
15666
|
+
)
|
|
15071
15667
|
};
|
|
15072
|
-
return [summaryMsg, ...history.slice(splitIdx)];
|
|
15073
15668
|
}
|
|
15074
15669
|
// ── ctx.checkpoint() ────────────────────────────────────────────────
|
|
15075
15670
|
/**
|
|
@@ -15749,12 +16344,7 @@ ${summaryResponse.content}`
|
|
|
15749
16344
|
}
|
|
15750
16345
|
// ── ctx.awaitHuman() ──────────────────────────────────────────────────
|
|
15751
16346
|
async awaitHuman(options) {
|
|
15752
|
-
|
|
15753
|
-
const startedAt = Date.now();
|
|
15754
|
-
for (const tracker of trackers ?? []) {
|
|
15755
|
-
if (tracker.activeHumanWaits++ === 0) tracker.humanWaitStartedAt = startedAt;
|
|
15756
|
-
}
|
|
15757
|
-
try {
|
|
16347
|
+
return pauseAskClocks(async () => {
|
|
15758
16348
|
if (this.spanManager) {
|
|
15759
16349
|
return await this.spanManager.withSpanAsync(
|
|
15760
16350
|
"axl.ctx.awaitHuman",
|
|
@@ -15771,16 +16361,7 @@ ${summaryResponse.content}`
|
|
|
15771
16361
|
);
|
|
15772
16362
|
}
|
|
15773
16363
|
return await this._awaitHumanImpl(options);
|
|
15774
|
-
}
|
|
15775
|
-
const finishedAt = Date.now();
|
|
15776
|
-
for (const tracker of trackers ?? []) {
|
|
15777
|
-
tracker.activeHumanWaits--;
|
|
15778
|
-
if (tracker.activeHumanWaits === 0 && tracker.humanWaitStartedAt !== void 0) {
|
|
15779
|
-
tracker.humanWaitMs += finishedAt - tracker.humanWaitStartedAt;
|
|
15780
|
-
tracker.humanWaitStartedAt = void 0;
|
|
15781
|
-
}
|
|
15782
|
-
}
|
|
15783
|
-
}
|
|
16364
|
+
});
|
|
15784
16365
|
}
|
|
15785
16366
|
async _awaitHumanImpl(options) {
|
|
15786
16367
|
const branchSignal = this.currentSignal;
|
|
@@ -16777,7 +17358,7 @@ function workflow(config) {
|
|
|
16777
17358
|
// src/runtime.ts
|
|
16778
17359
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
16779
17360
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
16780
|
-
import { AsyncLocalStorage as
|
|
17361
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
|
|
16781
17362
|
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
16782
17363
|
import { dirname } from "path";
|
|
16783
17364
|
|
|
@@ -17492,17 +18073,17 @@ var Session = class _Session {
|
|
|
17492
18073
|
throw new Error("SessionOptions.history.summaryModel is required when summarize is true");
|
|
17493
18074
|
}
|
|
17494
18075
|
const messagesToDrop = history.slice(0, history.length - maxMessages);
|
|
17495
|
-
const
|
|
17496
|
-
|
|
17497
|
-
|
|
17498
|
-
|
|
17499
|
-
|
|
18076
|
+
const summary = await this.runtime.summarizeMessages(
|
|
18077
|
+
messagesToDrop,
|
|
18078
|
+
summaryModel,
|
|
18079
|
+
cachedSummary ? { previousSummary: cachedSummary } : void 0
|
|
18080
|
+
);
|
|
17500
18081
|
await this.store.saveSessionMeta(this.sessionId, "summaryCache", summary);
|
|
17501
18082
|
cachedSummary = summary;
|
|
17502
18083
|
}
|
|
17503
18084
|
const trimmed = history.slice(-maxMessages);
|
|
17504
18085
|
history.length = 0;
|
|
17505
|
-
history.push(...trimmed);
|
|
18086
|
+
history.push(...trimmed.map(withoutAnthropicThinking));
|
|
17506
18087
|
}
|
|
17507
18088
|
const userMessage = { role: "user", content: preparedInput.content };
|
|
17508
18089
|
history.push(userMessage);
|
|
@@ -17512,7 +18093,10 @@ var Session = class _Session {
|
|
|
17512
18093
|
const metadata = {
|
|
17513
18094
|
sessionId: this.sessionId,
|
|
17514
18095
|
sessionHistory: history,
|
|
17515
|
-
...cachedSummary ? { summaryCache: cachedSummary } : {}
|
|
18096
|
+
...cachedSummary ? { summaryCache: cachedSummary } : {},
|
|
18097
|
+
// An opted-out session must leave nothing at rest, including the
|
|
18098
|
+
// agent-scoped ask-summary records the runtime would otherwise cache.
|
|
18099
|
+
...this.options.persist === false ? { sessionPersist: false } : {}
|
|
17516
18100
|
};
|
|
17517
18101
|
return { history, metadata };
|
|
17518
18102
|
}
|
|
@@ -18966,7 +19550,7 @@ function assertNoRemovedObservationCallbacks(options) {
|
|
|
18966
19550
|
`runtime.createContext() no longer accepts ${removed.join(", ")}. Observe ctx.events or use runtime.stream() instead. See docs/migration/stream-first-observation.md.`
|
|
18967
19551
|
);
|
|
18968
19552
|
}
|
|
18969
|
-
var costScopeStorage = new
|
|
19553
|
+
var costScopeStorage = new AsyncLocalStorage4();
|
|
18970
19554
|
function forwardAbortSignal(external, internal) {
|
|
18971
19555
|
if (!external) return () => {
|
|
18972
19556
|
};
|
|
@@ -20594,22 +21178,17 @@ var AxlRuntime = class extends EventEmitter2 {
|
|
|
20594
21178
|
/**
|
|
20595
21179
|
* Summarize a list of chat messages into a concise summary string.
|
|
20596
21180
|
* Used by Session to summarize dropped messages when history.summarize is enabled.
|
|
21181
|
+
* `previousSummary` is folded in so a rolling summary never loses what it
|
|
21182
|
+
* alone still carries. Shares its prompt and provider call with the
|
|
21183
|
+
* `AgentConfig.maxContext` summarizer (see `compaction.ts`). It runs outside
|
|
21184
|
+
* any workflow execution, so it emits no ask-scoped events.
|
|
20597
21185
|
*/
|
|
20598
|
-
async summarizeMessages(messages, modelUri) {
|
|
21186
|
+
async summarizeMessages(messages, modelUri, options) {
|
|
20599
21187
|
const { provider, model } = this.resolveProvider(modelUri);
|
|
20600
|
-
const response = await provider
|
|
20601
|
-
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
content: "Summarize the following conversation concisely, preserving key facts, decisions, and context needed for continuing the conversation."
|
|
20605
|
-
},
|
|
20606
|
-
{
|
|
20607
|
-
role: "user",
|
|
20608
|
-
content: messages.map((m) => `${m.role}: ${summarizeModelInput(m.content)}`).join("\n")
|
|
20609
|
-
}
|
|
20610
|
-
],
|
|
20611
|
-
{ model, maxTokens: 1024 }
|
|
20612
|
-
);
|
|
21188
|
+
const response = await requestSummary(provider, {
|
|
21189
|
+
model,
|
|
21190
|
+
prompt: buildSummaryPrompt(messages, options?.previousSummary)
|
|
21191
|
+
});
|
|
20613
21192
|
return response.content;
|
|
20614
21193
|
}
|
|
20615
21194
|
/** Get the state store (for testing and advanced use cases). */
|
|
@@ -22039,6 +22618,7 @@ export {
|
|
|
22039
22618
|
TranscriptionProviderRegistry,
|
|
22040
22619
|
UnsupportedEventSchemaVersionError,
|
|
22041
22620
|
UnsupportedModelInputError,
|
|
22621
|
+
UnsupportedModelOptionError,
|
|
22042
22622
|
UnsupportedTranscriptionInputError,
|
|
22043
22623
|
VLLM_PROFILE,
|
|
22044
22624
|
ValidationError,
|