@jeffusion/bungee-llms 4.5.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +901 -191
- package/dist/plugin-api.js +901 -191
- package/dist/token-accounting/session.d.ts +3 -1
- package/dist/token-accounting/types.d.ts +3 -0
- package/package.json +2 -2
package/dist/plugin-api.js
CHANGED
|
@@ -7059,7 +7059,8 @@ function readNumber(record, key) {
|
|
|
7059
7059
|
if (!record) {
|
|
7060
7060
|
return;
|
|
7061
7061
|
}
|
|
7062
|
-
|
|
7062
|
+
const value = record[key];
|
|
7063
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
7063
7064
|
}
|
|
7064
7065
|
function readRecord(record, key) {
|
|
7065
7066
|
if (!record) {
|
|
@@ -7132,7 +7133,7 @@ function clampTokens(value) {
|
|
|
7132
7133
|
if (value === undefined) {
|
|
7133
7134
|
return;
|
|
7134
7135
|
}
|
|
7135
|
-
return Math.max(0, Math.
|
|
7136
|
+
return Number.isFinite(value) ? Math.min(Number.MAX_SAFE_INTEGER, Math.max(0, Math.floor(value))) : undefined;
|
|
7136
7137
|
}
|
|
7137
7138
|
function buildBaseEvent(state, overrides) {
|
|
7138
7139
|
return {
|
|
@@ -7199,7 +7200,7 @@ function assertCanonicalTokenAccountingEventV2(event) {
|
|
|
7199
7200
|
throw new Error("Canonical token accounting event has invalid outputAuthority.");
|
|
7200
7201
|
}
|
|
7201
7202
|
for (const key of ["inputTokens", "outputTokens", "cacheReadTokens", "cacheWriteTokens"]) {
|
|
7202
|
-
if (event[key] !== undefined &&
|
|
7203
|
+
if (event[key] !== undefined && !(typeof event[key] === "number" && Number.isSafeInteger(event[key]) && event[key] >= 0)) {
|
|
7203
7204
|
throw new Error(`Canonical token accounting event has invalid numeric field: ${key}`);
|
|
7204
7205
|
}
|
|
7205
7206
|
}
|
|
@@ -7210,14 +7211,11 @@ function assertCanonicalTokenAccountingEventV2(event) {
|
|
|
7210
7211
|
throw new Error("Plugin aggregate fields logicalRequests/upstreamAttempts must not appear on single llms events.");
|
|
7211
7212
|
}
|
|
7212
7213
|
if (event.inputAuthority === "official") {
|
|
7213
|
-
if (
|
|
7214
|
+
if (!(typeof event.inputTokens === "number" && Number.isSafeInteger(event.inputTokens) && event.inputTokens >= 0)) {
|
|
7214
7215
|
throw new Error("Official inputAuthority requires inputTokens.");
|
|
7215
7216
|
}
|
|
7216
|
-
if (event.final && (asFiniteNumber(event.cacheReadTokens) === undefined || asFiniteNumber(event.cacheWriteTokens) === undefined)) {
|
|
7217
|
-
throw new Error("Official inputAuthority requires explicit cacheReadTokens and cacheWriteTokens, even when zero.");
|
|
7218
|
-
}
|
|
7219
7217
|
}
|
|
7220
|
-
if (event.outputAuthority === "official" &&
|
|
7218
|
+
if (event.outputAuthority === "official" && !(typeof event.outputTokens === "number" && Number.isSafeInteger(event.outputTokens) && event.outputTokens >= 0)) {
|
|
7221
7219
|
throw new Error("Official outputAuthority requires outputTokens.");
|
|
7222
7220
|
}
|
|
7223
7221
|
}
|
|
@@ -7277,6 +7275,444 @@ function getProviderTokenAccountingCapabilities(provider) {
|
|
|
7277
7275
|
return capabilities;
|
|
7278
7276
|
}
|
|
7279
7277
|
// src/token-accounting/session.ts
|
|
7278
|
+
var DEFERRED_MEDIA_KEYS = new Set([
|
|
7279
|
+
"image_url",
|
|
7280
|
+
"imageUrl",
|
|
7281
|
+
"inline_data",
|
|
7282
|
+
"inlineData",
|
|
7283
|
+
"file_data",
|
|
7284
|
+
"fileData",
|
|
7285
|
+
"file_uri",
|
|
7286
|
+
"fileUri",
|
|
7287
|
+
"file_url",
|
|
7288
|
+
"fileUrl",
|
|
7289
|
+
"file_id",
|
|
7290
|
+
"fileId",
|
|
7291
|
+
"input_audio",
|
|
7292
|
+
"inputAudio",
|
|
7293
|
+
"audio_url",
|
|
7294
|
+
"audioUrl",
|
|
7295
|
+
"input_video",
|
|
7296
|
+
"inputVideo",
|
|
7297
|
+
"video_url",
|
|
7298
|
+
"videoUrl"
|
|
7299
|
+
]);
|
|
7300
|
+
var DEFERRED_MEDIA_TYPES = new Set([
|
|
7301
|
+
"image",
|
|
7302
|
+
"input_image",
|
|
7303
|
+
"image_url",
|
|
7304
|
+
"input_audio",
|
|
7305
|
+
"audio",
|
|
7306
|
+
"input_video",
|
|
7307
|
+
"video",
|
|
7308
|
+
"input_file",
|
|
7309
|
+
"file"
|
|
7310
|
+
]);
|
|
7311
|
+
var DEFERRED_METADATA_KEYS = new Set([
|
|
7312
|
+
"model",
|
|
7313
|
+
"role",
|
|
7314
|
+
"type",
|
|
7315
|
+
"status",
|
|
7316
|
+
"index",
|
|
7317
|
+
"id",
|
|
7318
|
+
"mime_type",
|
|
7319
|
+
"mimeType",
|
|
7320
|
+
"detail"
|
|
7321
|
+
]);
|
|
7322
|
+
var MAX_STREAM_ESTIMATE_CHARS = 64 * 1024;
|
|
7323
|
+
var MAX_STREAM_ESTIMATE_FRAGMENTS = 4096;
|
|
7324
|
+
var MAX_INPUT_ESTIMATE_NODES = 4096;
|
|
7325
|
+
var MAX_DEFERRED_MODEL_CHARS = 256;
|
|
7326
|
+
function isDeferred(state) {
|
|
7327
|
+
return state.deferFinalization === true;
|
|
7328
|
+
}
|
|
7329
|
+
function setSessionModel(state, value) {
|
|
7330
|
+
const model = asString2(value) ?? state.model ?? "unknown";
|
|
7331
|
+
if (isDeferred(state) && model.length > MAX_DEFERRED_MODEL_CHARS) {
|
|
7332
|
+
state.model = model.slice(0, MAX_DEFERRED_MODEL_CHARS);
|
|
7333
|
+
state.requestEstimateTruncated = true;
|
|
7334
|
+
return;
|
|
7335
|
+
}
|
|
7336
|
+
state.model = model;
|
|
7337
|
+
}
|
|
7338
|
+
function observeOutput(state, value) {
|
|
7339
|
+
if (state.outputAuthority === "official")
|
|
7340
|
+
return;
|
|
7341
|
+
if (isDeferred(state) && typeof value === "string" && isMediaDataUri(value)) {
|
|
7342
|
+
state.estimateMediaSeen = true;
|
|
7343
|
+
return;
|
|
7344
|
+
}
|
|
7345
|
+
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
7346
|
+
if (!text)
|
|
7347
|
+
return;
|
|
7348
|
+
const estimateState = state;
|
|
7349
|
+
const remaining = MAX_STREAM_ESTIMATE_CHARS - (estimateState.estimateChars ?? 0);
|
|
7350
|
+
if (remaining <= 0) {
|
|
7351
|
+
estimateState.estimateTruncated = true;
|
|
7352
|
+
return;
|
|
7353
|
+
}
|
|
7354
|
+
if ((estimateState.estimateFragments?.length ?? 0) >= MAX_STREAM_ESTIMATE_FRAGMENTS) {
|
|
7355
|
+
estimateState.estimateTruncated = true;
|
|
7356
|
+
return;
|
|
7357
|
+
}
|
|
7358
|
+
const fragment = text.slice(0, remaining);
|
|
7359
|
+
(estimateState.estimateFragments ??= []).push(fragment);
|
|
7360
|
+
estimateState.estimateChars = (estimateState.estimateChars ?? 0) + fragment.length;
|
|
7361
|
+
if (fragment.length < text.length)
|
|
7362
|
+
estimateState.estimateTruncated = true;
|
|
7363
|
+
}
|
|
7364
|
+
function observeBoundedOutput(state, value) {
|
|
7365
|
+
if (state.outputAuthority === "official")
|
|
7366
|
+
return;
|
|
7367
|
+
if (!isDeferred(state)) {
|
|
7368
|
+
if (typeof value === "string") {
|
|
7369
|
+
observeOutput(state, value);
|
|
7370
|
+
return;
|
|
7371
|
+
}
|
|
7372
|
+
const bounded = boundedRequestSnapshot({ value });
|
|
7373
|
+
if (bounded.truncated)
|
|
7374
|
+
state.estimateTruncated = true;
|
|
7375
|
+
observeOutput(state, bounded.value.value);
|
|
7376
|
+
return;
|
|
7377
|
+
}
|
|
7378
|
+
const estimateState = state;
|
|
7379
|
+
const nodesLeft = MAX_INPUT_ESTIMATE_NODES - (estimateState.estimateNodes ?? 0);
|
|
7380
|
+
if (nodesLeft < 3) {
|
|
7381
|
+
estimateState.estimateTruncated = true;
|
|
7382
|
+
return;
|
|
7383
|
+
}
|
|
7384
|
+
const bounded = typeof value === "string" ? { value: { value: value.slice(0, MAX_STREAM_ESTIMATE_CHARS) }, truncated: value.length > MAX_STREAM_ESTIMATE_CHARS, nodesCopied: 0 } : boundedRequestSnapshot({ value }, Math.max(1, Math.floor(nodesLeft / 3)));
|
|
7385
|
+
estimateState.estimateNodes = (estimateState.estimateNodes ?? 0) + bounded.nodesCopied * 3;
|
|
7386
|
+
const filtered = stripDeferredMedia(bounded.value.value);
|
|
7387
|
+
if (bounded.truncated)
|
|
7388
|
+
estimateState.estimateTruncated = true;
|
|
7389
|
+
if (filtered.sawMedia)
|
|
7390
|
+
estimateState.estimateMediaSeen = true;
|
|
7391
|
+
if (filtered.hasContent)
|
|
7392
|
+
observeOutput(state, filtered.value);
|
|
7393
|
+
}
|
|
7394
|
+
function isMediaDataUri(value) {
|
|
7395
|
+
return /^data:(?:image|audio|video)\//i.test(value);
|
|
7396
|
+
}
|
|
7397
|
+
function stripDeferredMedia(value, key = "") {
|
|
7398
|
+
if (key === "tools" || key === "tool_calls" || key === "tool_use" || key === "functionCall" || key === "function_call" || key === "arguments" || key === "args") {
|
|
7399
|
+
return { value, sawMedia: false, hasContent: Array.isArray(value) ? value.length > 0 : value !== null && value !== undefined };
|
|
7400
|
+
}
|
|
7401
|
+
if (DEFERRED_MEDIA_KEYS.has(key))
|
|
7402
|
+
return { value: undefined, sawMedia: true, hasContent: false };
|
|
7403
|
+
if (typeof value === "string") {
|
|
7404
|
+
const dataUriPattern = /data:(?:image|audio|video)\/[^\s"'<>)}\]]+/gi;
|
|
7405
|
+
const stripped = value.replace(dataUriPattern, "");
|
|
7406
|
+
const sawMedia = stripped.length !== value.length;
|
|
7407
|
+
return { value: stripped || undefined, sawMedia, hasContent: stripped.length > 0 && !DEFERRED_METADATA_KEYS.has(key) };
|
|
7408
|
+
}
|
|
7409
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
7410
|
+
return { value, sawMedia: false, hasContent: !DEFERRED_METADATA_KEYS.has(key) };
|
|
7411
|
+
}
|
|
7412
|
+
if (Array.isArray(value)) {
|
|
7413
|
+
let sawMedia = false;
|
|
7414
|
+
let hasContent = false;
|
|
7415
|
+
const result = [];
|
|
7416
|
+
for (const item of value) {
|
|
7417
|
+
const filtered = stripDeferredMedia(item);
|
|
7418
|
+
sawMedia ||= filtered.sawMedia;
|
|
7419
|
+
hasContent ||= filtered.hasContent;
|
|
7420
|
+
if (filtered.value !== undefined)
|
|
7421
|
+
result.push(filtered.value);
|
|
7422
|
+
}
|
|
7423
|
+
return { value: result, sawMedia, hasContent };
|
|
7424
|
+
}
|
|
7425
|
+
if (!isRecord6(value))
|
|
7426
|
+
return { value, sawMedia: false, hasContent: false };
|
|
7427
|
+
if (asString2(value.type) === "tool_use" || asString2(value.type) === "function_call")
|
|
7428
|
+
return { value, sawMedia: false, hasContent: true };
|
|
7429
|
+
if (DEFERRED_MEDIA_TYPES.has(asString2(value.type) ?? ""))
|
|
7430
|
+
return { value: undefined, sawMedia: true, hasContent: false };
|
|
7431
|
+
const result = {};
|
|
7432
|
+
let sawMedia = false;
|
|
7433
|
+
let hasContent = false;
|
|
7434
|
+
for (const [childKey, child] of Object.entries(value)) {
|
|
7435
|
+
const filtered = stripDeferredMedia(child, childKey);
|
|
7436
|
+
sawMedia ||= filtered.sawMedia;
|
|
7437
|
+
hasContent ||= filtered.hasContent;
|
|
7438
|
+
if (filtered.value !== undefined)
|
|
7439
|
+
result[childKey] = filtered.value;
|
|
7440
|
+
}
|
|
7441
|
+
return { value: result, sawMedia, hasContent };
|
|
7442
|
+
}
|
|
7443
|
+
function clearObservedOutput(state) {
|
|
7444
|
+
const estimateState = state;
|
|
7445
|
+
estimateState.estimateFragments = undefined;
|
|
7446
|
+
estimateState.estimateChars = undefined;
|
|
7447
|
+
estimateState.estimateTruncated = false;
|
|
7448
|
+
estimateState.estimateMediaSeen = false;
|
|
7449
|
+
estimateState.estimateNodes = 0;
|
|
7450
|
+
}
|
|
7451
|
+
function estimatedStreamOutput(state) {
|
|
7452
|
+
const estimateState = state;
|
|
7453
|
+
const estimateChars = estimateState.estimateChars ?? 0;
|
|
7454
|
+
if (estimateChars === 0)
|
|
7455
|
+
return { authority: "none" };
|
|
7456
|
+
if (isDeferred(state)) {
|
|
7457
|
+
const tokens = clampTokens(countTextTokens("x".repeat(estimateChars)));
|
|
7458
|
+
return tokens === undefined ? { authority: "none" } : { tokens, authority: estimateState.estimateTruncated || estimateState.estimateMediaSeen ? "partial" : "heuristic" };
|
|
7459
|
+
}
|
|
7460
|
+
const tokens = clampTokens(countModelTextTokens(estimateState.estimateFragments.join(""), state.model));
|
|
7461
|
+
return tokens === undefined ? { authority: "none" } : { tokens, authority: estimateState.estimateTruncated ? "partial" : "local" };
|
|
7462
|
+
}
|
|
7463
|
+
function finalizeMissingStreamOutput(state, interrupted = false) {
|
|
7464
|
+
if (state.outputAuthority === "official")
|
|
7465
|
+
return;
|
|
7466
|
+
const estimate = estimatedStreamOutput(state);
|
|
7467
|
+
state.outputTokens = estimate.tokens;
|
|
7468
|
+
state.outputAuthority = interrupted && estimate.tokens !== undefined ? "partial" : estimate.authority;
|
|
7469
|
+
}
|
|
7470
|
+
function boundedRequestSnapshot(body, maxNodes = MAX_INPUT_ESTIMATE_NODES) {
|
|
7471
|
+
let remaining = MAX_STREAM_ESTIMATE_CHARS;
|
|
7472
|
+
let nodes = maxNodes;
|
|
7473
|
+
let truncated = false;
|
|
7474
|
+
const copy = (value) => {
|
|
7475
|
+
if (nodes <= 0 || remaining <= 0) {
|
|
7476
|
+
truncated = true;
|
|
7477
|
+
return;
|
|
7478
|
+
}
|
|
7479
|
+
nodes -= 1;
|
|
7480
|
+
if (typeof value === "string") {
|
|
7481
|
+
if (value.length > remaining) {
|
|
7482
|
+
truncated = true;
|
|
7483
|
+
const clipped = value.slice(0, remaining);
|
|
7484
|
+
remaining = 0;
|
|
7485
|
+
return clipped;
|
|
7486
|
+
}
|
|
7487
|
+
remaining -= value.length;
|
|
7488
|
+
return value;
|
|
7489
|
+
}
|
|
7490
|
+
if (value === null || typeof value === "number" || typeof value === "boolean")
|
|
7491
|
+
return value;
|
|
7492
|
+
if (Array.isArray(value)) {
|
|
7493
|
+
const result = [];
|
|
7494
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
7495
|
+
if (nodes <= 0 || remaining <= 0) {
|
|
7496
|
+
truncated = true;
|
|
7497
|
+
break;
|
|
7498
|
+
}
|
|
7499
|
+
result.push(copy(value[index]));
|
|
7500
|
+
}
|
|
7501
|
+
if (result.length < value.length)
|
|
7502
|
+
truncated = true;
|
|
7503
|
+
return result;
|
|
7504
|
+
}
|
|
7505
|
+
if (!isRecord6(value))
|
|
7506
|
+
return;
|
|
7507
|
+
const result = {};
|
|
7508
|
+
for (const key in value) {
|
|
7509
|
+
if (!Object.prototype.hasOwnProperty.call(value, key))
|
|
7510
|
+
continue;
|
|
7511
|
+
if (nodes <= 0 || remaining <= key.length) {
|
|
7512
|
+
truncated = true;
|
|
7513
|
+
break;
|
|
7514
|
+
}
|
|
7515
|
+
remaining -= key.length;
|
|
7516
|
+
result[key] = copy(value[key]);
|
|
7517
|
+
}
|
|
7518
|
+
return result;
|
|
7519
|
+
};
|
|
7520
|
+
return { value: copy(body), truncated, nodesCopied: maxNodes - nodes };
|
|
7521
|
+
}
|
|
7522
|
+
function storeRequestForEstimate(state, body, fields) {
|
|
7523
|
+
const relevant = {};
|
|
7524
|
+
if (body.model !== undefined)
|
|
7525
|
+
relevant.model = isDeferred(state) && typeof body.model === "string" ? body.model.slice(0, MAX_DEFERRED_MODEL_CHARS) : body.model;
|
|
7526
|
+
for (const field of fields) {
|
|
7527
|
+
if (Object.prototype.hasOwnProperty.call(body, field))
|
|
7528
|
+
relevant[field] = body[field];
|
|
7529
|
+
}
|
|
7530
|
+
const bounded = boundedRequestSnapshot(relevant);
|
|
7531
|
+
state.requestBody = bounded.value;
|
|
7532
|
+
state.requestEstimateTruncated = bounded.truncated || typeof body.model === "string" && isDeferred(state) && body.model.length > MAX_DEFERRED_MODEL_CHARS;
|
|
7533
|
+
}
|
|
7534
|
+
function estimateMissingInput(state) {
|
|
7535
|
+
if (state.estimatedInputAuthority === "official")
|
|
7536
|
+
return;
|
|
7537
|
+
const requestBody = state.requestBody;
|
|
7538
|
+
if (!requestBody) {
|
|
7539
|
+
state.estimatedInputTokens = undefined;
|
|
7540
|
+
state.estimatedInputAuthority = "none";
|
|
7541
|
+
return;
|
|
7542
|
+
}
|
|
7543
|
+
const hasInput = state.provider === "openai" ? requestBody.input !== undefined || requestBody.messages !== undefined : state.provider === "anthropic" ? requestBody.system !== undefined || requestBody.messages !== undefined : requestBody.contents !== undefined || requestBody.systemInstruction !== undefined;
|
|
7544
|
+
if (!hasInput) {
|
|
7545
|
+
state.estimatedInputTokens = undefined;
|
|
7546
|
+
state.estimatedInputAuthority = "none";
|
|
7547
|
+
return;
|
|
7548
|
+
}
|
|
7549
|
+
const bounded = isDeferred(state) ? { value: requestBody, truncated: false } : boundedRequestSnapshot(requestBody);
|
|
7550
|
+
if (isDeferred(state)) {
|
|
7551
|
+
const filtered = stripDeferredMedia(bounded.value);
|
|
7552
|
+
const estimateBody = { ...filtered.value };
|
|
7553
|
+
delete estimateBody.model;
|
|
7554
|
+
const hasToolSchema = Array.isArray(estimateBody.tools) && estimateBody.tools.length > 0;
|
|
7555
|
+
const hasContent = filtered.hasContent || hasToolSchema;
|
|
7556
|
+
if (!hasContent) {
|
|
7557
|
+
state.estimatedInputTokens = undefined;
|
|
7558
|
+
state.estimatedInputAuthority = "none";
|
|
7559
|
+
return;
|
|
7560
|
+
}
|
|
7561
|
+
state.estimatedInputTokens = clampTokens(countJsonLikeTokens(estimateBody));
|
|
7562
|
+
state.estimatedInputAuthority = bounded.truncated || state.requestEstimateTruncated || filtered.sawMedia ? "partial" : "heuristic";
|
|
7563
|
+
return;
|
|
7564
|
+
}
|
|
7565
|
+
const estimate = state.provider === "openai" ? estimateOpenAIInputTokens(bounded.value) : state.provider === "anthropic" ? estimateAnthropicInputTokens(bounded.value) : estimateGeminiInputTokens(bounded.value);
|
|
7566
|
+
state.estimatedInputTokens = estimate;
|
|
7567
|
+
state.estimatedInputAuthority = bounded.truncated || state.requestEstimateTruncated ? "partial" : "local";
|
|
7568
|
+
}
|
|
7569
|
+
function hasOpenAIOutput(body) {
|
|
7570
|
+
if (Array.isArray(body.output) && body.output.length > 0)
|
|
7571
|
+
return true;
|
|
7572
|
+
return Array.isArray(body.choices) && body.choices.some((choice) => {
|
|
7573
|
+
if (!isRecord6(choice))
|
|
7574
|
+
return false;
|
|
7575
|
+
const message = readRecord(choice, "message") ?? readRecord(choice, "delta");
|
|
7576
|
+
return !!message && (message.content !== undefined && message.content !== null || Array.isArray(message.tool_calls) && message.tool_calls.length > 0);
|
|
7577
|
+
});
|
|
7578
|
+
}
|
|
7579
|
+
function hasAnthropicOutput(body) {
|
|
7580
|
+
return Array.isArray(body.content) && body.content.length > 0;
|
|
7581
|
+
}
|
|
7582
|
+
function observeAnthropicOutput(state, body) {
|
|
7583
|
+
const blocks = Array.isArray(body.content) ? body.content : [];
|
|
7584
|
+
for (let index = 0;index < blocks.length && index < MAX_INPUT_ESTIMATE_NODES; index += 1) {
|
|
7585
|
+
observeBoundedOutput(state, blocks[index]);
|
|
7586
|
+
}
|
|
7587
|
+
if (blocks.length > MAX_INPUT_ESTIMATE_NODES && isDeferred(state))
|
|
7588
|
+
state.estimateTruncated = true;
|
|
7589
|
+
}
|
|
7590
|
+
function hasGeminiOutput(body) {
|
|
7591
|
+
return Array.isArray(body.candidates) && body.candidates.some((candidate) => {
|
|
7592
|
+
const parts = readRecord(candidate, "content")?.parts;
|
|
7593
|
+
return Array.isArray(parts) && parts.length > 0;
|
|
7594
|
+
});
|
|
7595
|
+
}
|
|
7596
|
+
function isErrorResponse(body) {
|
|
7597
|
+
const status = asString2(body.status)?.toLowerCase();
|
|
7598
|
+
const type = asString2(body.type)?.toLowerCase();
|
|
7599
|
+
return body.error !== undefined || status === "error" || status === "failed" || type === "error" || type?.endsWith(".error") === true || type?.endsWith(".failed") === true;
|
|
7600
|
+
}
|
|
7601
|
+
function isDeferredFailure(body) {
|
|
7602
|
+
const status = asString2(body.status)?.toLowerCase();
|
|
7603
|
+
const type = asString2(body.type)?.toLowerCase();
|
|
7604
|
+
return isErrorResponse(body) || status === "incomplete" || type === "incomplete" || type?.endsWith(".incomplete") === true;
|
|
7605
|
+
}
|
|
7606
|
+
function observeOpenAIOutput(state, chunk, includeResponseSnapshot = true) {
|
|
7607
|
+
if (state.outputAuthority === "official")
|
|
7608
|
+
return;
|
|
7609
|
+
let nodes = MAX_INPUT_ESTIMATE_NODES;
|
|
7610
|
+
const truncated = () => {
|
|
7611
|
+
if (isDeferred(state))
|
|
7612
|
+
state.estimateTruncated = true;
|
|
7613
|
+
};
|
|
7614
|
+
const type = asString2(chunk.type);
|
|
7615
|
+
if (type === "response.output_text.delta") {
|
|
7616
|
+
if (isDeferred(state))
|
|
7617
|
+
observeBoundedOutput(state, chunk.delta);
|
|
7618
|
+
else
|
|
7619
|
+
observeOutput(state, chunk.delta);
|
|
7620
|
+
}
|
|
7621
|
+
if (type === "response.function_call_arguments.delta") {
|
|
7622
|
+
if (isDeferred(state))
|
|
7623
|
+
observeBoundedOutput(state, chunk.delta);
|
|
7624
|
+
else
|
|
7625
|
+
observeOutput(state, chunk.delta);
|
|
7626
|
+
}
|
|
7627
|
+
if (includeResponseSnapshot) {
|
|
7628
|
+
const response = readRecord(chunk, "response");
|
|
7629
|
+
const responseOutput = Array.isArray(response?.output) ? response.output : Array.isArray(chunk.output) ? chunk.output : undefined;
|
|
7630
|
+
if (responseOutput !== undefined) {
|
|
7631
|
+
if (isDeferred(state)) {
|
|
7632
|
+
const limit = Math.min(responseOutput.length, nodes);
|
|
7633
|
+
for (let index = 0;index < limit; index += 1, nodes -= 1) {
|
|
7634
|
+
observeBoundedOutput(state, responseOutput[index]);
|
|
7635
|
+
}
|
|
7636
|
+
if (responseOutput.length > limit)
|
|
7637
|
+
truncated();
|
|
7638
|
+
} else
|
|
7639
|
+
observeOutput(state, responseOutput);
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
7643
|
+
const choiceLimit = Math.min(choices.length, nodes);
|
|
7644
|
+
for (let index = 0;index < choiceLimit; index += 1, nodes -= 1) {
|
|
7645
|
+
const choice = choices[index];
|
|
7646
|
+
if (!isRecord6(choice))
|
|
7647
|
+
continue;
|
|
7648
|
+
const delta = readRecord(choice, "delta") ?? (isDeferred(state) ? readRecord(choice, "message") : undefined);
|
|
7649
|
+
if (delta?.content !== undefined) {
|
|
7650
|
+
if (isDeferred(state))
|
|
7651
|
+
observeBoundedOutput(state, delta.content);
|
|
7652
|
+
else
|
|
7653
|
+
observeOutput(state, delta.content);
|
|
7654
|
+
}
|
|
7655
|
+
const calls = Array.isArray(delta?.tool_calls) ? delta.tool_calls : [];
|
|
7656
|
+
const callLimit = Math.min(calls.length, nodes);
|
|
7657
|
+
for (let callIndex = 0;callIndex < callLimit; callIndex += 1, nodes -= 1) {
|
|
7658
|
+
const call = calls[callIndex];
|
|
7659
|
+
const fn = readRecord(call, "function");
|
|
7660
|
+
if (fn?.arguments !== undefined) {
|
|
7661
|
+
if (isDeferred(state))
|
|
7662
|
+
observeBoundedOutput(state, fn.arguments);
|
|
7663
|
+
else
|
|
7664
|
+
observeOutput(state, fn.arguments);
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
if (calls.length > callLimit)
|
|
7668
|
+
truncated();
|
|
7669
|
+
}
|
|
7670
|
+
if (choices.length > choiceLimit)
|
|
7671
|
+
truncated();
|
|
7672
|
+
}
|
|
7673
|
+
function replaceObservedOutput(state) {
|
|
7674
|
+
const estimateState = state;
|
|
7675
|
+
estimateState.estimateFragments = [];
|
|
7676
|
+
estimateState.estimateChars = 0;
|
|
7677
|
+
estimateState.estimateTruncated = false;
|
|
7678
|
+
estimateState.estimateMediaSeen = false;
|
|
7679
|
+
estimateState.estimateNodes = 0;
|
|
7680
|
+
}
|
|
7681
|
+
function observeGeminiOutput(state, chunk) {
|
|
7682
|
+
let nodes = MAX_INPUT_ESTIMATE_NODES;
|
|
7683
|
+
const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
|
|
7684
|
+
const candidateLimit = Math.min(candidates.length, nodes);
|
|
7685
|
+
for (let candidateIndex = 0;candidateIndex < candidateLimit; candidateIndex += 1, nodes -= 1) {
|
|
7686
|
+
const candidate = candidates[candidateIndex];
|
|
7687
|
+
const content = readRecord(candidate, "content");
|
|
7688
|
+
const parts = Array.isArray(content?.parts) ? content.parts : [];
|
|
7689
|
+
const partLimit = Math.min(parts.length, nodes);
|
|
7690
|
+
for (let partIndex = 0;partIndex < partLimit; partIndex += 1, nodes -= 1) {
|
|
7691
|
+
const part = parts[partIndex];
|
|
7692
|
+
if (!isRecord6(part))
|
|
7693
|
+
continue;
|
|
7694
|
+
if (isDeferred(state) && (part.inlineData !== undefined || part.inline_data !== undefined || part.fileData !== undefined || part.file_data !== undefined)) {
|
|
7695
|
+
state.estimateMediaSeen = true;
|
|
7696
|
+
}
|
|
7697
|
+
if (typeof part.text === "string") {
|
|
7698
|
+
if (isDeferred(state))
|
|
7699
|
+
observeBoundedOutput(state, part.text);
|
|
7700
|
+
else
|
|
7701
|
+
observeOutput(state, part.text);
|
|
7702
|
+
}
|
|
7703
|
+
if (part.functionCall !== undefined) {
|
|
7704
|
+
if (isDeferred(state))
|
|
7705
|
+
observeBoundedOutput(state, part.functionCall);
|
|
7706
|
+
else
|
|
7707
|
+
observeOutput(state, part.functionCall);
|
|
7708
|
+
}
|
|
7709
|
+
}
|
|
7710
|
+
if (parts.length > partLimit && isDeferred(state))
|
|
7711
|
+
state.estimateTruncated = true;
|
|
7712
|
+
}
|
|
7713
|
+
if (candidates.length > candidateLimit && isDeferred(state))
|
|
7714
|
+
state.estimateTruncated = true;
|
|
7715
|
+
}
|
|
7280
7716
|
function countOpenAIStringTokens(value, model) {
|
|
7281
7717
|
return countModelTextTokens(asString2(value) ?? "", model);
|
|
7282
7718
|
}
|
|
@@ -7323,12 +7759,9 @@ function estimateOpenAIMessageTokens(message, model) {
|
|
|
7323
7759
|
const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
|
|
7324
7760
|
return 4 + countOpenAIStringTokens(message.role, model) + countOpenAIStringTokens(message.name, model) + countOpenAIStringTokens(message.tool_call_id, model) + estimateOpenAIMessageContent(content, model) + toolCalls.reduce((total, toolCall) => total + estimateOpenAIToolCallTokens(toolCall, model), 0);
|
|
7325
7761
|
}
|
|
7326
|
-
function
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
total += value ?? 0;
|
|
7330
|
-
}
|
|
7331
|
-
return total;
|
|
7762
|
+
function safeTokenSum(...values) {
|
|
7763
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
7764
|
+
return Number.isSafeInteger(total) && total >= 0 ? total : undefined;
|
|
7332
7765
|
}
|
|
7333
7766
|
function estimateGeminiInlineDataTokens(inlineData) {
|
|
7334
7767
|
const mimeType = asString2(inlineData.mimeType)?.toLowerCase() ?? "";
|
|
@@ -7349,53 +7782,6 @@ function estimateGeminiFunctionCallTokens(functionCall) {
|
|
|
7349
7782
|
function estimateGeminiFunctionResponseTokens(functionResponse) {
|
|
7350
7783
|
return 12 + countTextTokens(asString2(functionResponse.name) ?? "") + countJsonLikeTokens(functionResponse.response);
|
|
7351
7784
|
}
|
|
7352
|
-
function getAnthropicSessionState(state) {
|
|
7353
|
-
const anthropicState = state;
|
|
7354
|
-
if (!anthropicState.anthropicContentBlocks) {
|
|
7355
|
-
anthropicState.anthropicContentBlocks = new Map;
|
|
7356
|
-
}
|
|
7357
|
-
return anthropicState;
|
|
7358
|
-
}
|
|
7359
|
-
function tryParseJsonRecord(value) {
|
|
7360
|
-
if (!value) {
|
|
7361
|
-
return;
|
|
7362
|
-
}
|
|
7363
|
-
try {
|
|
7364
|
-
const parsed = JSON.parse(value);
|
|
7365
|
-
return isRecord6(parsed) ? parsed : undefined;
|
|
7366
|
-
} catch {
|
|
7367
|
-
return;
|
|
7368
|
-
}
|
|
7369
|
-
}
|
|
7370
|
-
function estimateAnthropicContentBlockTokens(block) {
|
|
7371
|
-
if (block.type === "text") {
|
|
7372
|
-
return countTextTokens(block.text ?? "");
|
|
7373
|
-
}
|
|
7374
|
-
if (block.type === "tool_use") {
|
|
7375
|
-
const parsedInput = tryParseJsonRecord(block.toolInputJson);
|
|
7376
|
-
return countJsonLikeTokens({
|
|
7377
|
-
type: "tool_use",
|
|
7378
|
-
id: block.toolUseId,
|
|
7379
|
-
name: block.toolName,
|
|
7380
|
-
input: parsedInput ?? (block.toolInputJson ? { partial_json: block.toolInputJson } : {})
|
|
7381
|
-
});
|
|
7382
|
-
}
|
|
7383
|
-
if (block.start) {
|
|
7384
|
-
return countJsonLikeTokens(block.start);
|
|
7385
|
-
}
|
|
7386
|
-
return 0;
|
|
7387
|
-
}
|
|
7388
|
-
function updateAnthropicEstimatedOutput(state) {
|
|
7389
|
-
const anthropicState = getAnthropicSessionState(state);
|
|
7390
|
-
anthropicState.anthropicEstimatedOutputTokens = clampTokens(Array.from(anthropicState.anthropicContentBlocks?.values() ?? []).reduce((total, block) => {
|
|
7391
|
-
return total + estimateAnthropicContentBlockTokens(block);
|
|
7392
|
-
}, 0)) ?? 0;
|
|
7393
|
-
if (state.outputAuthority === "partial" || state.outputAuthority === "official") {
|
|
7394
|
-
return;
|
|
7395
|
-
}
|
|
7396
|
-
state.outputTokens = anthropicState.anthropicEstimatedOutputTokens;
|
|
7397
|
-
state.outputAuthority = anthropicState.anthropicEstimatedOutputTokens > 0 ? "local" : "none";
|
|
7398
|
-
}
|
|
7399
7785
|
function buildAnthropicStreamingEvent(state, overrides = {}) {
|
|
7400
7786
|
return createPartialTokenAccountingEvent(state, {
|
|
7401
7787
|
inputTokens: state.estimatedInputTokens,
|
|
@@ -7430,6 +7816,9 @@ function estimateOpenAIMessageContent(content, model) {
|
|
|
7430
7816
|
}
|
|
7431
7817
|
function estimateOpenAIInputTokens(body) {
|
|
7432
7818
|
const model = asString2(body.model);
|
|
7819
|
+
if (body.input !== undefined) {
|
|
7820
|
+
return clampTokens(countOpenAIJsonLikeTokens(body.input, model) + 8) ?? 0;
|
|
7821
|
+
}
|
|
7433
7822
|
const messages = Array.isArray(body.messages) ? body.messages : [];
|
|
7434
7823
|
const messageTokens = messages.reduce((total, message) => total + estimateOpenAIMessageTokens(message, model), 0);
|
|
7435
7824
|
const tools = Array.isArray(body.tools) ? body.tools : [];
|
|
@@ -7448,12 +7837,24 @@ function estimateOpenAIResponseOutputTokens(body, model) {
|
|
|
7448
7837
|
return total + countOpenAIStringTokens(message?.role ?? delta?.role, model) + countOpenAIStringTokens(message?.tool_call_id, model) + estimateOpenAIMessageContent(message?.content ?? delta?.content, model) + toolCalls.reduce((toolTotal, toolCall) => toolTotal + estimateOpenAIToolCallTokens(toolCall, model), 0) + (asString2(choice.finish_reason) === "tool_calls" ? 4 : 0);
|
|
7449
7838
|
}, 0)) ?? 0;
|
|
7450
7839
|
}
|
|
7451
|
-
function
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
const
|
|
7456
|
-
return
|
|
7840
|
+
function openAIUsage(body) {
|
|
7841
|
+
return readRecord(readRecord(body, "response"), "usage") ?? readRecord(body, "usage");
|
|
7842
|
+
}
|
|
7843
|
+
function estimateOpenAIResponsesOutputTokens(response, model) {
|
|
7844
|
+
const output = Array.isArray(response.output) ? response.output : [];
|
|
7845
|
+
return clampTokens(output.reduce((total, item) => {
|
|
7846
|
+
if (!isRecord6(item))
|
|
7847
|
+
return total + countOpenAIJsonLikeTokens(item, model);
|
|
7848
|
+
const content = Array.isArray(item.content) ? item.content : [];
|
|
7849
|
+
return total + content.reduce((contentTotal, part) => {
|
|
7850
|
+
if (isRecord6(part) && typeof part.text === "string")
|
|
7851
|
+
return contentTotal + countOpenAIStringTokens(part.text, model);
|
|
7852
|
+
return contentTotal + countOpenAIJsonLikeTokens(part, model);
|
|
7853
|
+
}, 0) + countOpenAIStringTokens(item.arguments, model);
|
|
7854
|
+
}, 0)) ?? 0;
|
|
7855
|
+
}
|
|
7856
|
+
function isDoneSentinel(chunk) {
|
|
7857
|
+
return chunk.data === "[DONE]" || chunk.type === "[DONE]";
|
|
7457
7858
|
}
|
|
7458
7859
|
function estimateAnthropicInputTokens(body) {
|
|
7459
7860
|
const system = asString2(body.system) ?? "";
|
|
@@ -7511,71 +7912,193 @@ function createOpenAIAdapter() {
|
|
|
7511
7912
|
provider: "openai",
|
|
7512
7913
|
capabilities: getProviderTokenAccountingCapabilities("openai"),
|
|
7513
7914
|
consumeRequest(state, body) {
|
|
7514
|
-
state
|
|
7515
|
-
state
|
|
7516
|
-
state.estimatedInputTokens = estimateOpenAIInputTokens(body);
|
|
7517
|
-
state.estimatedInputAuthority = "local";
|
|
7915
|
+
storeRequestForEstimate(state, body, ["input", "messages", "tools"]);
|
|
7916
|
+
setSessionModel(state, body.model);
|
|
7518
7917
|
},
|
|
7519
7918
|
consumeResponse(state, body) {
|
|
7520
|
-
const usage =
|
|
7521
|
-
const promptTokens = readNumber(usage, "prompt_tokens");
|
|
7522
|
-
const completionTokens = readNumber(usage, "completion_tokens");
|
|
7523
|
-
const
|
|
7524
|
-
const
|
|
7919
|
+
const usage = openAIUsage(body);
|
|
7920
|
+
const promptTokens = readNumber(usage, "prompt_tokens") ?? readNumber(usage, "input_tokens");
|
|
7921
|
+
const completionTokens = readNumber(usage, "completion_tokens") ?? readNumber(usage, "output_tokens");
|
|
7922
|
+
const responseStatus = asString2(readRecord(body, "response")?.status) ?? asString2(body.status);
|
|
7923
|
+
const isIncomplete = responseStatus === "incomplete" || asString2(body.type) === "response.incomplete";
|
|
7924
|
+
const isFailed = responseStatus === "failed" || asString2(body.type) === "response.failed";
|
|
7925
|
+
const promptDetails = readRecord(usage, "prompt_tokens_details") ?? readRecord(usage, "input_tokens_details");
|
|
7926
|
+
const cacheReadTokens = readNumber(promptDetails, "cached_tokens");
|
|
7927
|
+
if (isDeferred(state)) {
|
|
7928
|
+
if (promptTokens !== undefined) {
|
|
7929
|
+
state.estimatedInputTokens = promptTokens;
|
|
7930
|
+
state.estimatedInputAuthority = "official";
|
|
7931
|
+
}
|
|
7932
|
+
if (completionTokens !== undefined) {
|
|
7933
|
+
state.outputTokens = completionTokens;
|
|
7934
|
+
state.outputAuthority = "official";
|
|
7935
|
+
clearObservedOutput(state);
|
|
7936
|
+
}
|
|
7937
|
+
if (cacheReadTokens !== undefined)
|
|
7938
|
+
state.cacheReadTokens = cacheReadTokens;
|
|
7939
|
+
if (!isIncomplete && !isFailed && !isErrorResponse(body))
|
|
7940
|
+
observeOpenAIOutput(state, body);
|
|
7941
|
+
state.protocolTerminalSeen = true;
|
|
7942
|
+
state.deferredOutcome = isIncomplete || isFailed || isErrorResponse(body) ? "failed" : "completed";
|
|
7943
|
+
return createPartialTokenAccountingEvent(state, {
|
|
7944
|
+
inputTokens: state.estimatedInputTokens,
|
|
7945
|
+
outputTokens: state.outputTokens,
|
|
7946
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
7947
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
7948
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
7949
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
7950
|
+
});
|
|
7951
|
+
}
|
|
7952
|
+
if (promptTokens === undefined)
|
|
7953
|
+
estimateMissingInput(state);
|
|
7954
|
+
const responseHasOutput = hasOpenAIOutput(body) && !isIncomplete && !isFailed && !isErrorResponse(body);
|
|
7955
|
+
const estimatedOutput = completionTokens === undefined && responseHasOutput ? Array.isArray(body.output) ? estimateOpenAIResponsesOutputTokens(body, state.model) : estimateOpenAIResponseOutputTokens(body, state.model) : undefined;
|
|
7525
7956
|
if (promptTokens !== undefined || completionTokens !== undefined) {
|
|
7526
7957
|
state.finalReceived = true;
|
|
7527
7958
|
return finalizeTokenAccountingEvent(state, {
|
|
7528
7959
|
inputTokens: promptTokens ?? state.estimatedInputTokens,
|
|
7529
|
-
outputTokens: completionTokens ??
|
|
7960
|
+
outputTokens: completionTokens ?? estimatedOutput,
|
|
7530
7961
|
cacheReadTokens,
|
|
7531
|
-
cacheWriteTokens:
|
|
7962
|
+
cacheWriteTokens: undefined,
|
|
7532
7963
|
inputAuthority: promptTokens !== undefined ? "official" : state.estimatedInputAuthority ?? "heuristic",
|
|
7533
|
-
outputAuthority: completionTokens !== undefined ? "official" : "
|
|
7534
|
-
});
|
|
7964
|
+
outputAuthority: completionTokens !== undefined ? "official" : estimatedOutput === undefined ? "none" : "local"
|
|
7965
|
+
}, isIncomplete || isFailed ? "failed" : "completed");
|
|
7535
7966
|
}
|
|
7536
|
-
const outputTokens =
|
|
7967
|
+
const outputTokens = estimatedOutput;
|
|
7968
|
+
state.finalReceived = true;
|
|
7537
7969
|
state.outputTokens = outputTokens;
|
|
7538
|
-
state.outputAuthority = "local";
|
|
7970
|
+
state.outputAuthority = outputTokens === undefined ? "none" : "local";
|
|
7539
7971
|
return finalizeTokenAccountingEvent(state, {
|
|
7540
7972
|
inputTokens: state.estimatedInputTokens,
|
|
7541
7973
|
outputTokens,
|
|
7542
|
-
inputAuthority: state.estimatedInputAuthority ?? "
|
|
7543
|
-
outputAuthority:
|
|
7544
|
-
});
|
|
7974
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
7975
|
+
outputAuthority: state.outputAuthority
|
|
7976
|
+
}, isIncomplete || isFailed ? "failed" : "completed");
|
|
7545
7977
|
},
|
|
7546
7978
|
consumeStreamChunk(state, chunk) {
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
const
|
|
7550
|
-
|
|
7979
|
+
if (state.finalReceived || isDoneSentinel(chunk))
|
|
7980
|
+
return null;
|
|
7981
|
+
const response = readRecord(chunk, "response");
|
|
7982
|
+
const usage = openAIUsage(chunk);
|
|
7983
|
+
const promptTokens = readNumber(usage, "prompt_tokens") ?? readNumber(usage, "input_tokens");
|
|
7984
|
+
const completionTokens = readNumber(usage, "completion_tokens") ?? readNumber(usage, "output_tokens");
|
|
7985
|
+
const promptDetails = readRecord(usage, "prompt_tokens_details") ?? readRecord(usage, "input_tokens_details");
|
|
7986
|
+
if (promptTokens !== undefined) {
|
|
7987
|
+
state.estimatedInputTokens = promptTokens;
|
|
7988
|
+
state.estimatedInputAuthority = "official";
|
|
7989
|
+
}
|
|
7990
|
+
if (completionTokens !== undefined) {
|
|
7991
|
+
state.outputTokens = completionTokens;
|
|
7992
|
+
state.outputAuthority = "official";
|
|
7993
|
+
clearObservedOutput(state);
|
|
7994
|
+
}
|
|
7995
|
+
const reportedCache = readNumber(promptDetails, "cached_tokens");
|
|
7996
|
+
if (reportedCache !== undefined)
|
|
7997
|
+
state.cacheReadTokens = reportedCache;
|
|
7998
|
+
const responseType = asString2(chunk.type);
|
|
7999
|
+
const responseStatus = asString2(response?.status);
|
|
8000
|
+
const responseCompleted = responseType === "response.completed" || responseStatus === "completed";
|
|
8001
|
+
observeOpenAIOutput(state, chunk, !responseCompleted);
|
|
8002
|
+
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
8003
|
+
if (choices.some((choice) => isRecord6(choice) && asString2(choice.finish_reason) !== undefined && choice.finish_reason !== null)) {
|
|
8004
|
+
state.protocolTerminalSeen = true;
|
|
8005
|
+
if (isDeferred(state))
|
|
8006
|
+
state.deferredOutcome = "completed";
|
|
8007
|
+
}
|
|
8008
|
+
if (isDeferred(state)) {
|
|
8009
|
+
if (responseCompleted) {
|
|
8010
|
+
state.deferredOutcome = "completed";
|
|
8011
|
+
state.protocolTerminalSeen = true;
|
|
8012
|
+
if (completionTokens === undefined && state.outputAuthority !== "official" && Array.isArray(response?.output)) {
|
|
8013
|
+
replaceObservedOutput(state);
|
|
8014
|
+
observeOpenAIOutput(state, { response });
|
|
8015
|
+
}
|
|
8016
|
+
} else if (responseType === "response.incomplete" || responseType === "response.failed" || responseStatus === "incomplete" || responseStatus === "failed") {
|
|
8017
|
+
state.deferredOutcome = "failed";
|
|
8018
|
+
state.protocolTerminalSeen = true;
|
|
8019
|
+
}
|
|
8020
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8021
|
+
inputTokens: state.estimatedInputTokens,
|
|
8022
|
+
outputTokens: state.outputTokens,
|
|
8023
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8024
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8025
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8026
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
8027
|
+
});
|
|
8028
|
+
}
|
|
8029
|
+
if (responseCompleted) {
|
|
8030
|
+
if (completionTokens === undefined && state.outputAuthority !== "official" && Array.isArray(response?.output)) {
|
|
8031
|
+
replaceObservedOutput(state);
|
|
8032
|
+
observeOpenAIOutput(state, { response });
|
|
8033
|
+
}
|
|
8034
|
+
if (completionTokens === undefined)
|
|
8035
|
+
finalizeMissingStreamOutput(state);
|
|
8036
|
+
if (promptTokens === undefined)
|
|
8037
|
+
estimateMissingInput(state);
|
|
7551
8038
|
state.finalReceived = true;
|
|
7552
8039
|
return finalizeTokenAccountingEvent(state, {
|
|
7553
8040
|
inputTokens: promptTokens ?? state.estimatedInputTokens,
|
|
7554
|
-
outputTokens: completionTokens ?? state.outputTokens
|
|
7555
|
-
cacheReadTokens: readNumber(readRecord(usage, "prompt_tokens_details"), "cached_tokens") ??
|
|
7556
|
-
cacheWriteTokens:
|
|
8041
|
+
outputTokens: completionTokens ?? state.outputTokens,
|
|
8042
|
+
cacheReadTokens: readNumber(readRecord(usage, "input_tokens_details") ?? readRecord(usage, "prompt_tokens_details"), "cached_tokens") ?? state.cacheReadTokens,
|
|
8043
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
7557
8044
|
inputAuthority: promptTokens !== undefined ? "official" : state.estimatedInputAuthority ?? "heuristic",
|
|
7558
|
-
outputAuthority: completionTokens !== undefined ? "official" : "
|
|
8045
|
+
outputAuthority: completionTokens !== undefined ? "official" : state.outputAuthority ?? "none"
|
|
7559
8046
|
});
|
|
7560
8047
|
}
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
8048
|
+
if (responseType === "response.incomplete" || responseType === "response.failed" || responseStatus === "incomplete" || responseStatus === "failed") {
|
|
8049
|
+
state.finalReceived = true;
|
|
8050
|
+
const promptDetails = readRecord(usage, "input_tokens_details") ?? readRecord(usage, "prompt_tokens_details");
|
|
8051
|
+
const input = promptTokens === undefined ? undefined : promptTokens;
|
|
8052
|
+
const output = completionTokens;
|
|
8053
|
+
state.estimatedInputTokens = input ?? state.estimatedInputTokens;
|
|
8054
|
+
state.outputTokens = output ?? state.outputTokens;
|
|
8055
|
+
state.cacheReadTokens = readNumber(promptDetails, "cached_tokens") ?? state.cacheReadTokens;
|
|
8056
|
+
if (output === undefined)
|
|
8057
|
+
finalizeMissingStreamOutput(state);
|
|
8058
|
+
if (input === undefined)
|
|
8059
|
+
estimateMissingInput(state);
|
|
8060
|
+
return finalizeTokenAccountingEvent(state, {
|
|
8061
|
+
inputTokens: input ?? state.estimatedInputTokens,
|
|
8062
|
+
outputTokens: output ?? state.outputTokens,
|
|
8063
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8064
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8065
|
+
inputAuthority: input !== undefined ? "official" : state.estimatedInputAuthority ?? "heuristic",
|
|
8066
|
+
outputAuthority: output !== undefined ? "official" : state.outputAuthority ?? "none"
|
|
8067
|
+
}, "failed");
|
|
7565
8068
|
}
|
|
7566
8069
|
return createPartialTokenAccountingEvent(state, {
|
|
8070
|
+
inputTokens: state.estimatedInputTokens,
|
|
7567
8071
|
outputTokens: state.outputTokens,
|
|
7568
|
-
|
|
7569
|
-
|
|
8072
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8073
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8074
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8075
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
7570
8076
|
});
|
|
7571
8077
|
},
|
|
7572
8078
|
finalizeAbortedStream(state) {
|
|
8079
|
+
finalizeMissingStreamOutput(state, true);
|
|
8080
|
+
estimateMissingInput(state);
|
|
7573
8081
|
return finalizeTokenAccountingEvent(state, {
|
|
7574
8082
|
inputTokens: state.estimatedInputTokens,
|
|
7575
|
-
outputTokens: state.outputTokens
|
|
7576
|
-
inputAuthority: state.estimatedInputAuthority ?? "
|
|
7577
|
-
outputAuthority: state.
|
|
8083
|
+
outputTokens: state.outputTokens,
|
|
8084
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8085
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
7578
8086
|
}, "aborted");
|
|
8087
|
+
},
|
|
8088
|
+
finalizeCompletedStream(state) {
|
|
8089
|
+
if (state.finalReceived)
|
|
8090
|
+
return createPartialTokenAccountingEvent(state);
|
|
8091
|
+
state.finalReceived = true;
|
|
8092
|
+
finalizeMissingStreamOutput(state);
|
|
8093
|
+
estimateMissingInput(state);
|
|
8094
|
+
return finalizeTokenAccountingEvent(state, {
|
|
8095
|
+
inputTokens: state.estimatedInputTokens,
|
|
8096
|
+
outputTokens: state.outputTokens,
|
|
8097
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8098
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8099
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8100
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
8101
|
+
}, state.deferredOutcome ?? (state.protocolTerminalSeen ? "completed" : "failed"));
|
|
7579
8102
|
}
|
|
7580
8103
|
};
|
|
7581
8104
|
}
|
|
@@ -7584,126 +8107,207 @@ function createAnthropicAdapter() {
|
|
|
7584
8107
|
provider: "anthropic",
|
|
7585
8108
|
capabilities: getProviderTokenAccountingCapabilities("anthropic"),
|
|
7586
8109
|
consumeRequest(state, body) {
|
|
7587
|
-
state
|
|
7588
|
-
state
|
|
7589
|
-
state.estimatedInputTokens = estimateAnthropicInputTokens(body);
|
|
7590
|
-
state.estimatedInputAuthority = "local";
|
|
8110
|
+
storeRequestForEstimate(state, body, ["system", "messages", "tools"]);
|
|
8111
|
+
setSessionModel(state, body.model);
|
|
7591
8112
|
},
|
|
7592
8113
|
consumeResponse(state, body) {
|
|
7593
8114
|
const usage = readRecord(body, "usage");
|
|
7594
8115
|
const inputTokens = readNumber(usage, "input_tokens");
|
|
7595
8116
|
const outputTokens = readNumber(usage, "output_tokens");
|
|
7596
|
-
const cacheWriteTokens = readNumber(usage, "cache_creation_input_tokens")
|
|
7597
|
-
const cacheReadTokens = readNumber(usage, "cache_read_input_tokens")
|
|
7598
|
-
|
|
8117
|
+
const cacheWriteTokens = readNumber(usage, "cache_creation_input_tokens");
|
|
8118
|
+
const cacheReadTokens = readNumber(usage, "cache_read_input_tokens");
|
|
8119
|
+
const totalInputTokens = inputTokens === undefined ? undefined : safeTokenSum(inputTokens, cacheWriteTokens ?? 0, cacheReadTokens ?? 0);
|
|
8120
|
+
if (isDeferred(state)) {
|
|
8121
|
+
if (totalInputTokens !== undefined) {
|
|
8122
|
+
state.estimatedInputTokens = totalInputTokens;
|
|
8123
|
+
state.estimatedInputAuthority = "official";
|
|
8124
|
+
}
|
|
8125
|
+
if (outputTokens !== undefined) {
|
|
8126
|
+
state.outputTokens = outputTokens;
|
|
8127
|
+
state.outputAuthority = "official";
|
|
8128
|
+
clearObservedOutput(state);
|
|
8129
|
+
}
|
|
8130
|
+
if (cacheReadTokens !== undefined)
|
|
8131
|
+
state.cacheReadTokens = cacheReadTokens;
|
|
8132
|
+
if (cacheWriteTokens !== undefined)
|
|
8133
|
+
state.cacheWriteTokens = cacheWriteTokens;
|
|
8134
|
+
const failed = isDeferredFailure(body);
|
|
8135
|
+
if (!failed)
|
|
8136
|
+
observeAnthropicOutput(state, body);
|
|
8137
|
+
state.protocolTerminalSeen = true;
|
|
8138
|
+
state.deferredOutcome = failed ? "failed" : "completed";
|
|
8139
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8140
|
+
inputTokens: state.estimatedInputTokens,
|
|
8141
|
+
outputTokens: state.outputTokens,
|
|
8142
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8143
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8144
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8145
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
8146
|
+
});
|
|
8147
|
+
}
|
|
8148
|
+
if (totalInputTokens === undefined)
|
|
8149
|
+
estimateMissingInput(state);
|
|
8150
|
+
const estimatedOutput = outputTokens === undefined && hasAnthropicOutput(body) && !isErrorResponse(body) ? estimateAnthropicOutputTokens(body) : undefined;
|
|
8151
|
+
if (usage && (inputTokens !== undefined || outputTokens !== undefined || readNumber(usage, "cache_creation_input_tokens") !== undefined || readNumber(usage, "cache_read_input_tokens") !== undefined)) {
|
|
7599
8152
|
state.finalReceived = true;
|
|
7600
8153
|
return finalizeTokenAccountingEvent(state, {
|
|
7601
|
-
inputTokens:
|
|
7602
|
-
outputTokens: outputTokens ??
|
|
8154
|
+
inputTokens: totalInputTokens ?? state.estimatedInputTokens,
|
|
8155
|
+
outputTokens: outputTokens ?? estimatedOutput,
|
|
7603
8156
|
cacheReadTokens,
|
|
7604
8157
|
cacheWriteTokens,
|
|
7605
|
-
inputAuthority:
|
|
7606
|
-
outputAuthority: outputTokens !== undefined ? "official" : "
|
|
8158
|
+
inputAuthority: totalInputTokens !== undefined ? "official" : state.estimatedInputAuthority ?? "heuristic",
|
|
8159
|
+
outputAuthority: outputTokens !== undefined ? "official" : estimatedOutput === undefined ? "none" : "local"
|
|
7607
8160
|
});
|
|
7608
8161
|
}
|
|
7609
8162
|
return finalizeTokenAccountingEvent(state, {
|
|
7610
8163
|
inputTokens: state.estimatedInputTokens,
|
|
7611
|
-
outputTokens:
|
|
7612
|
-
inputAuthority: state.estimatedInputAuthority ?? "
|
|
7613
|
-
outputAuthority: "local"
|
|
8164
|
+
outputTokens: estimatedOutput,
|
|
8165
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8166
|
+
outputAuthority: estimatedOutput === undefined ? "none" : "local"
|
|
7614
8167
|
});
|
|
7615
8168
|
},
|
|
7616
8169
|
consumeStreamChunk(state, chunk) {
|
|
7617
|
-
|
|
8170
|
+
if (state.finalReceived || isDoneSentinel(chunk))
|
|
8171
|
+
return null;
|
|
7618
8172
|
const type = asString2(chunk.type);
|
|
8173
|
+
if (isDeferred(state) && type === "error") {
|
|
8174
|
+
state.protocolTerminalSeen = true;
|
|
8175
|
+
state.deferredOutcome = "failed";
|
|
8176
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8177
|
+
inputTokens: state.estimatedInputTokens,
|
|
8178
|
+
outputTokens: state.outputTokens,
|
|
8179
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8180
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8181
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8182
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
8183
|
+
});
|
|
8184
|
+
}
|
|
7619
8185
|
if (type === "message_start") {
|
|
7620
8186
|
const message = readRecord(chunk, "message");
|
|
7621
8187
|
const usage = readRecord(message, "usage");
|
|
7622
|
-
state
|
|
7623
|
-
state.
|
|
7624
|
-
state.
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
state.
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
8188
|
+
setSessionModel(state, message?.model);
|
|
8189
|
+
state.cacheWriteTokens = readNumber(usage, "cache_creation_input_tokens") ?? state.cacheWriteTokens;
|
|
8190
|
+
state.cacheReadTokens = readNumber(usage, "cache_read_input_tokens") ?? state.cacheReadTokens;
|
|
8191
|
+
const rawInputTokens = readNumber(usage, "input_tokens");
|
|
8192
|
+
const totalInputTokens = rawInputTokens === undefined ? undefined : safeTokenSum(rawInputTokens, state.cacheWriteTokens ?? 0, state.cacheReadTokens ?? 0);
|
|
8193
|
+
state.estimatedInputTokens = totalInputTokens ?? state.estimatedInputTokens;
|
|
8194
|
+
if (totalInputTokens !== undefined)
|
|
8195
|
+
state.estimatedInputAuthority = "official";
|
|
8196
|
+
const initialOutputTokens = readNumber(usage, "output_tokens");
|
|
8197
|
+
state.outputTokens = initialOutputTokens ?? state.outputTokens;
|
|
8198
|
+
state.outputAuthority = initialOutputTokens !== undefined ? "official" : "none";
|
|
8199
|
+
if (initialOutputTokens !== undefined)
|
|
8200
|
+
clearObservedOutput(state);
|
|
7631
8201
|
return buildAnthropicStreamingEvent(state, {
|
|
7632
8202
|
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
7633
|
-
outputAuthority:
|
|
8203
|
+
outputAuthority: state.outputAuthority
|
|
7634
8204
|
});
|
|
7635
8205
|
}
|
|
7636
8206
|
if (type === "content_block_start") {
|
|
7637
|
-
const index = readNumber(chunk, "index") ?? 0;
|
|
7638
8207
|
const contentBlock = readRecord(chunk, "content_block");
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
toolInputJson: ""
|
|
7646
|
-
});
|
|
7647
|
-
updateAnthropicEstimatedOutput(state);
|
|
8208
|
+
if (contentBlock?.text !== undefined) {
|
|
8209
|
+
if (isDeferred(state))
|
|
8210
|
+
observeBoundedOutput(state, contentBlock.text);
|
|
8211
|
+
else
|
|
8212
|
+
observeOutput(state, contentBlock.text);
|
|
8213
|
+
}
|
|
7648
8214
|
return buildAnthropicStreamingEvent(state);
|
|
7649
8215
|
}
|
|
7650
8216
|
if (type === "content_block_delta") {
|
|
7651
|
-
const index = readNumber(chunk, "index") ?? 0;
|
|
7652
8217
|
const delta = readRecord(chunk, "delta");
|
|
7653
|
-
const block = anthropicState.anthropicContentBlocks?.get(index) ?? {};
|
|
7654
8218
|
const deltaType = asString2(delta?.type);
|
|
7655
8219
|
if (deltaType === "text_delta") {
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
block.type = block.type ?? "tool_use";
|
|
7661
|
-
block.toolInputJson = `${block.toolInputJson ?? ""}${asString2(delta?.partial_json) ?? ""}`;
|
|
8220
|
+
if (isDeferred(state))
|
|
8221
|
+
observeBoundedOutput(state, delta?.text);
|
|
8222
|
+
else
|
|
8223
|
+
observeOutput(state, delta?.text);
|
|
7662
8224
|
}
|
|
7663
|
-
|
|
7664
|
-
|
|
8225
|
+
if (deltaType === "input_json_delta")
|
|
8226
|
+
observeOutput(state, delta?.partial_json);
|
|
7665
8227
|
return buildAnthropicStreamingEvent(state);
|
|
7666
8228
|
}
|
|
7667
8229
|
if (type === "content_block_stop") {
|
|
7668
|
-
updateAnthropicEstimatedOutput(state);
|
|
7669
8230
|
return buildAnthropicStreamingEvent(state);
|
|
7670
8231
|
}
|
|
7671
8232
|
if (type === "message_delta") {
|
|
7672
8233
|
const usage = readRecord(chunk, "usage");
|
|
7673
8234
|
const outputTokens = readNumber(usage, "output_tokens");
|
|
8235
|
+
const rawInputTokens = readNumber(usage, "input_tokens");
|
|
8236
|
+
if (rawInputTokens !== undefined) {
|
|
8237
|
+
state.cacheWriteTokens = readNumber(usage, "cache_creation_input_tokens") ?? state.cacheWriteTokens;
|
|
8238
|
+
state.cacheReadTokens = readNumber(usage, "cache_read_input_tokens") ?? state.cacheReadTokens;
|
|
8239
|
+
const totalInput = safeTokenSum(rawInputTokens, state.cacheWriteTokens ?? 0, state.cacheReadTokens ?? 0);
|
|
8240
|
+
state.estimatedInputTokens = totalInput ?? state.estimatedInputTokens;
|
|
8241
|
+
if (totalInput !== undefined)
|
|
8242
|
+
state.estimatedInputAuthority = "official";
|
|
8243
|
+
}
|
|
7674
8244
|
if (outputTokens !== undefined) {
|
|
7675
8245
|
state.outputTokens = outputTokens;
|
|
7676
|
-
state.outputAuthority = "
|
|
8246
|
+
state.outputAuthority = "official";
|
|
8247
|
+
clearObservedOutput(state);
|
|
7677
8248
|
}
|
|
8249
|
+
state.cacheWriteTokens = readNumber(usage, "cache_creation_input_tokens") ?? state.cacheWriteTokens;
|
|
8250
|
+
state.cacheReadTokens = readNumber(usage, "cache_read_input_tokens") ?? state.cacheReadTokens;
|
|
7678
8251
|
return buildAnthropicStreamingEvent(state, {
|
|
7679
|
-
outputAuthority: state.outputTokens !== undefined ? "
|
|
8252
|
+
outputAuthority: state.outputTokens !== undefined ? state.outputAuthority ?? "none" : "none"
|
|
7680
8253
|
});
|
|
7681
8254
|
}
|
|
7682
8255
|
if (type === "message_stop") {
|
|
7683
8256
|
if (state.finalReceived) {
|
|
7684
8257
|
return null;
|
|
7685
8258
|
}
|
|
8259
|
+
state.protocolTerminalSeen = true;
|
|
8260
|
+
if (isDeferred(state)) {
|
|
8261
|
+
state.deferredOutcome ??= "completed";
|
|
8262
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8263
|
+
inputTokens: state.estimatedInputTokens,
|
|
8264
|
+
outputTokens: state.outputTokens,
|
|
8265
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8266
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8267
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8268
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
8269
|
+
});
|
|
8270
|
+
}
|
|
7686
8271
|
state.finalReceived = true;
|
|
8272
|
+
finalizeMissingStreamOutput(state);
|
|
8273
|
+
estimateMissingInput(state);
|
|
7687
8274
|
return finalizeTokenAccountingEvent(state, {
|
|
7688
8275
|
inputTokens: state.estimatedInputTokens,
|
|
7689
8276
|
outputTokens: state.outputTokens,
|
|
7690
|
-
cacheReadTokens: state.cacheReadTokens
|
|
7691
|
-
cacheWriteTokens: state.cacheWriteTokens
|
|
8277
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8278
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
7692
8279
|
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
7693
|
-
outputAuthority: state.outputAuthority
|
|
8280
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
7694
8281
|
});
|
|
7695
8282
|
}
|
|
7696
8283
|
return null;
|
|
7697
8284
|
},
|
|
7698
8285
|
finalizeAbortedStream(state) {
|
|
8286
|
+
finalizeMissingStreamOutput(state, true);
|
|
8287
|
+
estimateMissingInput(state);
|
|
7699
8288
|
return finalizeTokenAccountingEvent(state, {
|
|
7700
8289
|
inputTokens: state.estimatedInputTokens,
|
|
7701
8290
|
outputTokens: state.outputTokens,
|
|
7702
|
-
cacheReadTokens: state.cacheReadTokens
|
|
7703
|
-
cacheWriteTokens: state.cacheWriteTokens
|
|
7704
|
-
inputAuthority: state.estimatedInputAuthority ?? "
|
|
8291
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8292
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8293
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
7705
8294
|
outputAuthority: state.outputTokens !== undefined ? state.outputAuthority ?? "partial" : "none"
|
|
7706
8295
|
}, "aborted");
|
|
8296
|
+
},
|
|
8297
|
+
finalizeCompletedStream(state) {
|
|
8298
|
+
if (state.finalReceived)
|
|
8299
|
+
return buildAnthropicStreamingEvent(state);
|
|
8300
|
+
state.finalReceived = true;
|
|
8301
|
+
finalizeMissingStreamOutput(state);
|
|
8302
|
+
estimateMissingInput(state);
|
|
8303
|
+
return finalizeTokenAccountingEvent(state, {
|
|
8304
|
+
inputTokens: state.estimatedInputTokens,
|
|
8305
|
+
outputTokens: state.outputTokens,
|
|
8306
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8307
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8308
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8309
|
+
outputAuthority: state.outputTokens !== undefined ? state.outputAuthority ?? "partial" : "none"
|
|
8310
|
+
}, state.deferredOutcome ?? (state.protocolTerminalSeen ? "completed" : "failed"));
|
|
7707
8311
|
}
|
|
7708
8312
|
};
|
|
7709
8313
|
}
|
|
@@ -7712,71 +8316,158 @@ function createGeminiAdapter() {
|
|
|
7712
8316
|
provider: "gemini",
|
|
7713
8317
|
capabilities: getProviderTokenAccountingCapabilities("gemini"),
|
|
7714
8318
|
consumeRequest(state, body) {
|
|
7715
|
-
state
|
|
7716
|
-
state
|
|
7717
|
-
state.estimatedInputTokens = estimateGeminiInputTokens(body);
|
|
7718
|
-
state.estimatedInputAuthority = "local";
|
|
8319
|
+
storeRequestForEstimate(state, body, ["contents", "systemInstruction"]);
|
|
8320
|
+
setSessionModel(state, body.model);
|
|
7719
8321
|
},
|
|
7720
8322
|
consumeResponse(state, body) {
|
|
7721
8323
|
const usageMetadata = readRecord(body, "usageMetadata");
|
|
7722
8324
|
const promptTokenCount = readNumber(usageMetadata, "promptTokenCount");
|
|
7723
8325
|
const candidatesTokenCount = readNumber(usageMetadata, "candidatesTokenCount");
|
|
7724
|
-
const
|
|
8326
|
+
const thoughtsTokenCount = readNumber(usageMetadata, "thoughtsTokenCount") ?? 0;
|
|
8327
|
+
const toolUsePromptTokenCount = readNumber(usageMetadata, "toolUsePromptTokenCount") ?? 0;
|
|
8328
|
+
const cachedContentTokenCount = readNumber(usageMetadata, "cachedContentTokenCount");
|
|
8329
|
+
if (isDeferred(state)) {
|
|
8330
|
+
const input = promptTokenCount === undefined ? undefined : safeTokenSum(promptTokenCount, toolUsePromptTokenCount);
|
|
8331
|
+
const output = candidatesTokenCount === undefined ? undefined : safeTokenSum(candidatesTokenCount, thoughtsTokenCount);
|
|
8332
|
+
if (input !== undefined) {
|
|
8333
|
+
state.estimatedInputTokens = input;
|
|
8334
|
+
state.estimatedInputAuthority = "official";
|
|
8335
|
+
}
|
|
8336
|
+
if (output !== undefined) {
|
|
8337
|
+
state.outputTokens = output;
|
|
8338
|
+
state.outputAuthority = "official";
|
|
8339
|
+
clearObservedOutput(state);
|
|
8340
|
+
}
|
|
8341
|
+
if (cachedContentTokenCount !== undefined)
|
|
8342
|
+
state.cacheReadTokens = cachedContentTokenCount;
|
|
8343
|
+
const failed = isDeferredFailure(body);
|
|
8344
|
+
if (!failed)
|
|
8345
|
+
observeGeminiOutput(state, body);
|
|
8346
|
+
state.protocolTerminalSeen = true;
|
|
8347
|
+
state.deferredOutcome = failed ? "failed" : "completed";
|
|
8348
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8349
|
+
inputTokens: state.estimatedInputTokens,
|
|
8350
|
+
outputTokens: state.outputTokens,
|
|
8351
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8352
|
+
cacheWriteTokens: undefined,
|
|
8353
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8354
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
8355
|
+
});
|
|
8356
|
+
}
|
|
8357
|
+
if (promptTokenCount === undefined)
|
|
8358
|
+
estimateMissingInput(state);
|
|
8359
|
+
const estimatedOutput = candidatesTokenCount === undefined && hasGeminiOutput(body) && !isErrorResponse(body) ? estimateGeminiOutputTokens(body) : undefined;
|
|
7725
8360
|
if (promptTokenCount !== undefined || candidatesTokenCount !== undefined) {
|
|
7726
8361
|
state.finalReceived = true;
|
|
7727
8362
|
return finalizeTokenAccountingEvent(state, {
|
|
7728
|
-
inputTokens: promptTokenCount ?? state.estimatedInputTokens,
|
|
7729
|
-
outputTokens: candidatesTokenCount
|
|
8363
|
+
inputTokens: promptTokenCount === undefined ? state.estimatedInputTokens : safeTokenSum(promptTokenCount, toolUsePromptTokenCount) ?? state.estimatedInputTokens,
|
|
8364
|
+
outputTokens: candidatesTokenCount === undefined ? estimatedOutput : safeTokenSum(candidatesTokenCount, thoughtsTokenCount) ?? estimatedOutput,
|
|
7730
8365
|
cacheReadTokens: cachedContentTokenCount,
|
|
7731
|
-
cacheWriteTokens:
|
|
7732
|
-
inputAuthority: promptTokenCount !== undefined ? "official" : state.estimatedInputAuthority ?? "heuristic",
|
|
7733
|
-
outputAuthority: candidatesTokenCount !== undefined ? "official" : "
|
|
8366
|
+
cacheWriteTokens: undefined,
|
|
8367
|
+
inputAuthority: promptTokenCount !== undefined && safeTokenSum(promptTokenCount, toolUsePromptTokenCount) !== undefined ? "official" : state.estimatedInputAuthority ?? "heuristic",
|
|
8368
|
+
outputAuthority: candidatesTokenCount !== undefined && safeTokenSum(candidatesTokenCount, thoughtsTokenCount) !== undefined ? "official" : estimatedOutput === undefined ? "none" : "local"
|
|
7734
8369
|
});
|
|
7735
8370
|
}
|
|
7736
|
-
const outputTokens =
|
|
8371
|
+
const outputTokens = estimatedOutput;
|
|
8372
|
+
state.finalReceived = true;
|
|
7737
8373
|
state.outputTokens = outputTokens;
|
|
7738
|
-
state.outputAuthority = "local";
|
|
8374
|
+
state.outputAuthority = outputTokens === undefined ? "none" : "local";
|
|
7739
8375
|
return finalizeTokenAccountingEvent(state, {
|
|
7740
8376
|
inputTokens: state.estimatedInputTokens,
|
|
7741
8377
|
outputTokens,
|
|
7742
|
-
inputAuthority: state.estimatedInputAuthority ?? "
|
|
7743
|
-
outputAuthority:
|
|
8378
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8379
|
+
outputAuthority: state.outputAuthority
|
|
7744
8380
|
});
|
|
7745
8381
|
},
|
|
7746
8382
|
consumeStreamChunk(state, chunk) {
|
|
8383
|
+
if (state.finalReceived || isDoneSentinel(chunk))
|
|
8384
|
+
return null;
|
|
8385
|
+
observeGeminiOutput(state, chunk);
|
|
7747
8386
|
const usageMetadata = readRecord(chunk, "usageMetadata");
|
|
7748
8387
|
const promptTokenCount = readNumber(usageMetadata, "promptTokenCount");
|
|
7749
8388
|
const candidatesTokenCount = readNumber(usageMetadata, "candidatesTokenCount");
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
8389
|
+
const thoughtsTokenCount = readNumber(usageMetadata, "thoughtsTokenCount") ?? 0;
|
|
8390
|
+
const toolUsePromptTokenCount = readNumber(usageMetadata, "toolUsePromptTokenCount") ?? 0;
|
|
8391
|
+
const reportedCacheRead = readNumber(usageMetadata, "cachedContentTokenCount");
|
|
8392
|
+
const candidates = Array.isArray(chunk.candidates) ? chunk.candidates : [];
|
|
8393
|
+
if (candidates.some((candidate) => isRecord6(candidate) && asString2(candidate.finishReason) !== undefined)) {
|
|
8394
|
+
state.protocolTerminalSeen = true;
|
|
8395
|
+
if (isDeferred(state))
|
|
8396
|
+
state.deferredOutcome ??= "completed";
|
|
8397
|
+
}
|
|
8398
|
+
if (isDeferred(state) && isDeferredFailure(chunk)) {
|
|
8399
|
+
state.protocolTerminalSeen = true;
|
|
8400
|
+
state.deferredOutcome = "failed";
|
|
8401
|
+
}
|
|
8402
|
+
if (isDeferred(state) && reportedCacheRead !== undefined && promptTokenCount === undefined && candidatesTokenCount === undefined) {
|
|
8403
|
+
state.cacheReadTokens = reportedCacheRead;
|
|
8404
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8405
|
+
inputTokens: state.estimatedInputTokens,
|
|
8406
|
+
outputTokens: state.outputTokens,
|
|
8407
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8408
|
+
cacheWriteTokens: undefined,
|
|
8409
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8410
|
+
outputAuthority: state.outputAuthority ?? "none"
|
|
7759
8411
|
});
|
|
7760
8412
|
}
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
state.
|
|
8413
|
+
if (promptTokenCount !== undefined || candidatesTokenCount !== undefined) {
|
|
8414
|
+
const input = promptTokenCount === undefined ? undefined : safeTokenSum(promptTokenCount, toolUsePromptTokenCount);
|
|
8415
|
+
const output = candidatesTokenCount === undefined ? undefined : safeTokenSum(candidatesTokenCount, thoughtsTokenCount);
|
|
8416
|
+
state.estimatedInputTokens = input ?? state.estimatedInputTokens;
|
|
8417
|
+
if (input !== undefined)
|
|
8418
|
+
state.estimatedInputAuthority = "official";
|
|
8419
|
+
state.outputTokens = output ?? state.outputTokens;
|
|
8420
|
+
if (output !== undefined) {
|
|
8421
|
+
state.outputAuthority = "official";
|
|
8422
|
+
clearObservedOutput(state);
|
|
8423
|
+
}
|
|
8424
|
+
const cacheRead = readNumber(usageMetadata, "cachedContentTokenCount");
|
|
8425
|
+
if (cacheRead !== undefined)
|
|
8426
|
+
state.cacheReadTokens = cacheRead;
|
|
8427
|
+
return createPartialTokenAccountingEvent(state, {
|
|
8428
|
+
inputTokens: state.estimatedInputTokens,
|
|
8429
|
+
outputTokens: state.outputTokens,
|
|
8430
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8431
|
+
cacheWriteTokens: undefined,
|
|
8432
|
+
inputAuthority: state.estimatedInputAuthority ?? "heuristic",
|
|
8433
|
+
outputAuthority: state.outputAuthority ?? "partial"
|
|
8434
|
+
});
|
|
7765
8435
|
}
|
|
7766
8436
|
return createPartialTokenAccountingEvent(state, {
|
|
7767
8437
|
inputTokens: state.estimatedInputTokens,
|
|
7768
8438
|
outputTokens: state.outputTokens,
|
|
8439
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8440
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
7769
8441
|
inputAuthority: state.estimatedInputAuthority ?? "heuristic",
|
|
7770
|
-
outputAuthority: state.outputTokens !== undefined ? "partial" : "none"
|
|
8442
|
+
outputAuthority: state.outputAuthority ?? (state.outputTokens !== undefined ? "partial" : "none")
|
|
7771
8443
|
});
|
|
7772
8444
|
},
|
|
7773
8445
|
finalizeAbortedStream(state) {
|
|
8446
|
+
finalizeMissingStreamOutput(state, true);
|
|
8447
|
+
estimateMissingInput(state);
|
|
7774
8448
|
return finalizeTokenAccountingEvent(state, {
|
|
7775
8449
|
inputTokens: state.estimatedInputTokens,
|
|
7776
8450
|
outputTokens: state.outputTokens,
|
|
7777
|
-
|
|
7778
|
-
|
|
8451
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8452
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8453
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8454
|
+
outputAuthority: state.outputAuthority ?? (state.outputTokens !== undefined ? "partial" : "none")
|
|
7779
8455
|
}, "aborted");
|
|
8456
|
+
},
|
|
8457
|
+
finalizeCompletedStream(state) {
|
|
8458
|
+
if (state.finalReceived)
|
|
8459
|
+
return createPartialTokenAccountingEvent(state);
|
|
8460
|
+
state.finalReceived = true;
|
|
8461
|
+
finalizeMissingStreamOutput(state);
|
|
8462
|
+
estimateMissingInput(state);
|
|
8463
|
+
return finalizeTokenAccountingEvent(state, {
|
|
8464
|
+
inputTokens: state.estimatedInputTokens,
|
|
8465
|
+
outputTokens: state.outputTokens,
|
|
8466
|
+
cacheReadTokens: state.cacheReadTokens,
|
|
8467
|
+
cacheWriteTokens: state.cacheWriteTokens,
|
|
8468
|
+
inputAuthority: state.estimatedInputAuthority ?? "none",
|
|
8469
|
+
outputAuthority: state.outputAuthority ?? (state.outputTokens !== undefined ? "partial" : "none")
|
|
8470
|
+
}, state.deferredOutcome ?? (state.protocolTerminalSeen ? "completed" : "failed"));
|
|
7780
8471
|
}
|
|
7781
8472
|
};
|
|
7782
8473
|
}
|
|
@@ -7795,8 +8486,9 @@ function getProviderAdapter(provider) {
|
|
|
7795
8486
|
}
|
|
7796
8487
|
return adapter;
|
|
7797
8488
|
}
|
|
7798
|
-
function createTokenAccountingSession(input) {
|
|
8489
|
+
function createTokenAccountingSession(input, options = {}) {
|
|
7799
8490
|
const adapter = getProviderAdapter(input.provider);
|
|
8491
|
+
let terminalEvent;
|
|
7800
8492
|
const state = {
|
|
7801
8493
|
provider: adapter.provider,
|
|
7802
8494
|
routeId: input.routeId,
|
|
@@ -7805,20 +8497,38 @@ function createTokenAccountingSession(input) {
|
|
|
7805
8497
|
attemptId: input.attemptId,
|
|
7806
8498
|
streaming: input.streaming,
|
|
7807
8499
|
model: input.model,
|
|
7808
|
-
finalReceived: false
|
|
8500
|
+
finalReceived: false,
|
|
8501
|
+
deferFinalization: options.deferFinalization === true
|
|
7809
8502
|
};
|
|
7810
8503
|
return {
|
|
7811
8504
|
consumeRequest({ body }) {
|
|
7812
8505
|
adapter.consumeRequest(state, body);
|
|
7813
8506
|
},
|
|
7814
8507
|
consumeResponse({ body }) {
|
|
7815
|
-
|
|
8508
|
+
const event = adapter.consumeResponse(state, body);
|
|
8509
|
+
if (event.final || event.outcome !== "completed")
|
|
8510
|
+
terminalEvent = event;
|
|
8511
|
+
return event;
|
|
7816
8512
|
},
|
|
7817
8513
|
consumeStreamChunk({ chunk }) {
|
|
7818
|
-
|
|
8514
|
+
const event = adapter.consumeStreamChunk(state, chunk);
|
|
8515
|
+
if (event && (event.final || event.outcome !== "completed"))
|
|
8516
|
+
terminalEvent = event;
|
|
8517
|
+
return event;
|
|
8518
|
+
},
|
|
8519
|
+
finalizeCompletedStream() {
|
|
8520
|
+
if (terminalEvent)
|
|
8521
|
+
return terminalEvent;
|
|
8522
|
+
const event = adapter.finalizeCompletedStream(state);
|
|
8523
|
+
terminalEvent = event;
|
|
8524
|
+
return event;
|
|
7819
8525
|
},
|
|
7820
8526
|
finalizeAbortedStream() {
|
|
7821
|
-
|
|
8527
|
+
if (terminalEvent)
|
|
8528
|
+
return terminalEvent;
|
|
8529
|
+
const event = adapter.finalizeAbortedStream(state);
|
|
8530
|
+
terminalEvent = event;
|
|
8531
|
+
return event;
|
|
7822
8532
|
}
|
|
7823
8533
|
};
|
|
7824
8534
|
}
|