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