@genesislcap/ai-assistant 15.11.0 → 15.12.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/ai-assistant.api.json +135 -0
- package/dist/ai-assistant.d.ts +75 -3
- package/dist/chat-driver.cjs +540 -117
- package/dist/chat-driver.cjs.map +4 -4
- package/dist/chat-driver.mjs +524 -116
- package/dist/chat-driver.mjs.map +4 -4
- package/dist/custom-elements.json +1822 -1483
- package/dist/dts/chat-driver-node.d.ts +5 -2
- package/dist/dts/chat-driver-node.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.d.ts +20 -3
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts +2 -0
- package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts +2 -0
- package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts.map +1 -0
- package/dist/dts/config/config.d.ts +39 -2
- package/dist/dts/config/config.d.ts.map +1 -1
- package/dist/dts/config/define-stateful-agent.d.ts +15 -1
- package/dist/dts/config/define-stateful-agent.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/utils/strip-agent-handlers.d.ts +1 -1
- package/dist/dts/utils/sum-usage.d.ts +37 -4
- package/dist/dts/utils/sum-usage.d.ts.map +1 -1
- package/dist/dts/utils/usage-rows.d.ts +102 -0
- package/dist/dts/utils/usage-rows.d.ts.map +1 -0
- package/dist/dts/utils/usage-rows.test.d.ts +2 -0
- package/dist/dts/utils/usage-rows.test.d.ts.map +1 -0
- package/dist/esm/chat-driver-node.js +36 -1
- package/dist/esm/components/chat-driver/chat-driver.js +73 -10
- package/dist/esm/components/chat-driver/chat-driver.thinking-policy.test.js +137 -0
- package/dist/esm/components/chat-driver/chat-driver.trace-capture.test.js +200 -0
- package/dist/esm/config/define-stateful-agent.js +11 -0
- package/dist/esm/main/main.template.js +20 -1
- package/dist/esm/utils/strip-agent-handlers.js +1 -1
- package/dist/esm/utils/sum-usage.js +37 -4
- package/dist/esm/utils/usage-rows.js +90 -0
- package/dist/esm/utils/usage-rows.test.js +189 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -17
- package/src/chat-driver-node.ts +58 -0
- package/src/components/chat-driver/chat-driver.thinking-policy.test.ts +185 -0
- package/src/components/chat-driver/chat-driver.trace-capture.test.ts +251 -0
- package/src/components/chat-driver/chat-driver.ts +90 -10
- package/src/config/config.ts +50 -1
- package/src/config/define-stateful-agent.ts +37 -0
- package/src/main/main.template.ts +19 -1
- package/src/utils/strip-agent-handlers.ts +1 -1
- package/src/utils/sum-usage.ts +37 -4
- package/src/utils/usage-rows.test.ts +237 -0
- package/src/utils/usage-rows.ts +187 -0
package/dist/chat-driver.cjs
CHANGED
|
@@ -19,10 +19,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// src/chat-driver-node.ts
|
|
20
20
|
var chat_driver_node_exports = {};
|
|
21
21
|
__export(chat_driver_node_exports, {
|
|
22
|
+
ANTHROPIC_CACHE_READ_MULTIPLIER: () => ANTHROPIC_CACHE_READ_MULTIPLIER,
|
|
23
|
+
ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER: () => ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER,
|
|
24
|
+
ANTHROPIC_CACHE_WRITE_5M_MULTIPLIER: () => ANTHROPIC_CACHE_WRITE_5M_MULTIPLIER,
|
|
22
25
|
AgenticActivityBus: () => AgenticActivityBus,
|
|
23
26
|
AnthropicProvider: () => AnthropicProvider,
|
|
24
27
|
AnthropicTransport: () => AnthropicTransport,
|
|
25
28
|
ChatDriver: () => ChatDriver,
|
|
29
|
+
GEMINI_CACHED_INPUT_MULTIPLIER: () => GEMINI_CACHED_INPUT_MULTIPLIER,
|
|
30
|
+
GEMINI_LONG_CONTEXT_THRESHOLD: () => GEMINI_LONG_CONTEXT_THRESHOLD,
|
|
26
31
|
GeminiProvider: () => GeminiProvider,
|
|
27
32
|
GeminiTransport: () => GeminiTransport,
|
|
28
33
|
MutableAIProviderRegistry: () => MutableAIProviderRegistry,
|
|
@@ -31,17 +36,27 @@ __export(chat_driver_node_exports, {
|
|
|
31
36
|
REQUEST_CONTINUATION_TOOL: () => REQUEST_CONTINUATION_TOOL,
|
|
32
37
|
SUPPORTED_ANTHROPIC_MODEL_IDS: () => SUPPORTED_ANTHROPIC_MODEL_IDS,
|
|
33
38
|
SUPPORTED_GEMINI_MODEL_IDS: () => SUPPORTED_GEMINI_MODEL_IDS,
|
|
39
|
+
addUsage: () => addUsage,
|
|
34
40
|
agenticActivityBus: () => agenticActivityBus,
|
|
41
|
+
anthropicRatesFor: () => anthropicRatesFor,
|
|
42
|
+
anthropicTokenCost: () => anthropicTokenCost,
|
|
35
43
|
assembleDebugLog: () => assembleDebugLog,
|
|
36
44
|
buildTimelineEntries: () => buildTimelineEntries,
|
|
37
45
|
clearSession: () => clearSession,
|
|
38
46
|
defineAgent: () => defineAgent,
|
|
39
47
|
defineStatefulAgent: () => defineStatefulAgent,
|
|
48
|
+
emptyUsage: () => emptyUsage,
|
|
40
49
|
friendlyFallbackAgent: () => friendlyFallbackAgent,
|
|
50
|
+
geminiRatesFor: () => geminiRatesFor,
|
|
51
|
+
geminiTokenCost: () => geminiTokenCost,
|
|
41
52
|
getMetaEvents: () => getMetaEvents,
|
|
42
53
|
isObservableAIProviderRegistry: () => isObservableAIProviderRegistry,
|
|
43
54
|
restoreMachine: () => restoreMachine,
|
|
44
|
-
strictFallbackAgent: () => strictFallbackAgent
|
|
55
|
+
strictFallbackAgent: () => strictFallbackAgent,
|
|
56
|
+
sumUsage: () => sumUsage,
|
|
57
|
+
totalTokens: () => totalTokens,
|
|
58
|
+
usageRows: () => usageRows,
|
|
59
|
+
vendorOfModel: () => vendorOfModel
|
|
45
60
|
});
|
|
46
61
|
module.exports = __toCommonJS(chat_driver_node_exports);
|
|
47
62
|
|
|
@@ -1105,6 +1120,13 @@ var SUPPORTED_ANTHROPIC_MODEL_IDS = [
|
|
|
1105
1120
|
"claude-sonnet-4-6",
|
|
1106
1121
|
"claude-haiku-4-5-20251001"
|
|
1107
1122
|
];
|
|
1123
|
+
function vendorOfModel(modelId) {
|
|
1124
|
+
if (SUPPORTED_ANTHROPIC_MODEL_IDS.includes(modelId))
|
|
1125
|
+
return "anthropic";
|
|
1126
|
+
if (SUPPORTED_GEMINI_MODEL_IDS.includes(modelId))
|
|
1127
|
+
return "gemini";
|
|
1128
|
+
return void 0;
|
|
1129
|
+
}
|
|
1108
1130
|
|
|
1109
1131
|
// ../../foundation-ai/dist/esm/utils/temperature.js
|
|
1110
1132
|
var DEFAULT_ANCHOR = 0.5;
|
|
@@ -1113,6 +1135,106 @@ function scaleTemperature(normalized, { defaultTemp, maxTemp }) {
|
|
|
1113
1135
|
return t <= DEFAULT_ANCHOR ? t / DEFAULT_ANCHOR * defaultTemp : defaultTemp + (t - DEFAULT_ANCHOR) / (1 - DEFAULT_ANCHOR) * (maxTemp - defaultTemp);
|
|
1114
1136
|
}
|
|
1115
1137
|
|
|
1138
|
+
// ../../foundation-ai/dist/esm/utils/token-cost.js
|
|
1139
|
+
var TOKENS_PER_MILLION = 1e6;
|
|
1140
|
+
var ANTHROPIC_PRICING = {
|
|
1141
|
+
"claude-haiku-4-5-20251001": { promptPerMillion: 1, candidatePerMillion: 5 },
|
|
1142
|
+
// Fable 5 — Anthropic's most capable widely-released model; priced above Opus tier.
|
|
1143
|
+
"claude-fable-5": { promptPerMillion: 10, candidatePerMillion: 50 },
|
|
1144
|
+
// Opus 4.7 / 4.8 — same $5 / $25 per MTok. Stated per model rather than shared through a
|
|
1145
|
+
// fall-through, so neither is ever "whatever was left over".
|
|
1146
|
+
"claude-opus-4-8": { promptPerMillion: 5, candidatePerMillion: 25 },
|
|
1147
|
+
"claude-opus-4-7": { promptPerMillion: 5, candidatePerMillion: 25 },
|
|
1148
|
+
// Sonnet 5 is $2 / $10 — its OWN tier, and CHEAPER than the older Sonnet 4.6 below.
|
|
1149
|
+
//
|
|
1150
|
+
// This launched as an introductory rate through 2026-08-31, and an earlier version of this
|
|
1151
|
+
// table deliberately charged the $3 / $15 standard rate instead, on the reasoning that the
|
|
1152
|
+
// introductory period would lapse. Anthropic has since confirmed $2 / $10 as the permanent
|
|
1153
|
+
// standard price and cancelled the scheduled increase, so that reasoning is dead and the old
|
|
1154
|
+
// figure over-charged every Sonnet 5 request by 50%.
|
|
1155
|
+
// https://platform.claude.com/docs/en/about-claude/pricing#model-pricing
|
|
1156
|
+
"claude-sonnet-5": { promptPerMillion: 2, candidatePerMillion: 10 },
|
|
1157
|
+
// Sonnet 4.6 remains on the older $3 / $15 Sonnet tier — the newer model is the cheaper one.
|
|
1158
|
+
"claude-sonnet-4-6": { promptPerMillion: 3, candidatePerMillion: 15 }
|
|
1159
|
+
};
|
|
1160
|
+
function anthropicRatesFor(model) {
|
|
1161
|
+
return ANTHROPIC_PRICING[model];
|
|
1162
|
+
}
|
|
1163
|
+
var ANTHROPIC_CACHE_READ_MULTIPLIER = 0.1;
|
|
1164
|
+
var ANTHROPIC_CACHE_WRITE_5M_MULTIPLIER = 1.25;
|
|
1165
|
+
var ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER = 2;
|
|
1166
|
+
function anthropicTokenCost(model, usage) {
|
|
1167
|
+
const { promptPerMillion, candidatePerMillion } = anthropicRatesFor(model);
|
|
1168
|
+
const m = TOKENS_PER_MILLION;
|
|
1169
|
+
const cacheWrite5mTokens = Math.max(0, usage.cacheWriteTokens - usage.cacheWrite1hTokens);
|
|
1170
|
+
const promptCost = usage.uncachedInputTokens / m * promptPerMillion;
|
|
1171
|
+
const cacheReadCost = usage.cacheReadTokens / m * promptPerMillion * ANTHROPIC_CACHE_READ_MULTIPLIER;
|
|
1172
|
+
const cacheWriteCost = cacheWrite5mTokens / m * promptPerMillion * ANTHROPIC_CACHE_WRITE_5M_MULTIPLIER + usage.cacheWrite1hTokens / m * promptPerMillion * ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER;
|
|
1173
|
+
const candidateCost = usage.outputTokens / m * candidatePerMillion;
|
|
1174
|
+
const cacheReadFull = usage.cacheReadTokens / m * promptPerMillion;
|
|
1175
|
+
const cacheWriteFull = usage.cacheWriteTokens / m * promptPerMillion;
|
|
1176
|
+
return {
|
|
1177
|
+
costUsd: promptCost + cacheReadCost + cacheWriteCost + candidateCost,
|
|
1178
|
+
savedUsd: cacheReadFull - cacheReadCost + (cacheWriteFull - cacheWriteCost),
|
|
1179
|
+
breakdown: {
|
|
1180
|
+
promptUsd: promptCost,
|
|
1181
|
+
cacheReadUsd: cacheReadCost,
|
|
1182
|
+
cacheWriteUsd: cacheWriteCost,
|
|
1183
|
+
candidateUsd: candidateCost
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
var GEMINI_LONG_CONTEXT_THRESHOLD = 2e5;
|
|
1188
|
+
var GEMINI_CACHED_INPUT_MULTIPLIER = 0.1;
|
|
1189
|
+
var GEMINI_PRICING = {
|
|
1190
|
+
"gemini-2.5-flash-lite": {
|
|
1191
|
+
kind: "flat",
|
|
1192
|
+
rate: { promptPerMillion: 0.1, candidatePerMillion: 0.4 }
|
|
1193
|
+
},
|
|
1194
|
+
"gemini-2.5-flash": { kind: "flat", rate: { promptPerMillion: 0.3, candidatePerMillion: 2.5 } },
|
|
1195
|
+
"gemini-2.5-pro": {
|
|
1196
|
+
kind: "tiered",
|
|
1197
|
+
standard: { promptPerMillion: 1.25, candidatePerMillion: 10 },
|
|
1198
|
+
longContext: { promptPerMillion: 2.5, candidatePerMillion: 15 }
|
|
1199
|
+
},
|
|
1200
|
+
"gemini-3.1-flash-lite": {
|
|
1201
|
+
kind: "flat",
|
|
1202
|
+
rate: { promptPerMillion: 0.25, candidatePerMillion: 1.5 }
|
|
1203
|
+
},
|
|
1204
|
+
"gemini-3.5-flash": { kind: "flat", rate: { promptPerMillion: 1.5, candidatePerMillion: 9 } },
|
|
1205
|
+
"gemini-3.1-pro-preview": {
|
|
1206
|
+
kind: "tiered",
|
|
1207
|
+
standard: { promptPerMillion: 2, candidatePerMillion: 12 },
|
|
1208
|
+
longContext: { promptPerMillion: 4, candidatePerMillion: 18 }
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
function geminiRatesFor(model, promptTokens) {
|
|
1212
|
+
const pricing = GEMINI_PRICING[model];
|
|
1213
|
+
if (pricing.kind === "flat") {
|
|
1214
|
+
return pricing.rate;
|
|
1215
|
+
}
|
|
1216
|
+
return promptTokens > GEMINI_LONG_CONTEXT_THRESHOLD ? pricing.longContext : pricing.standard;
|
|
1217
|
+
}
|
|
1218
|
+
function geminiTokenCost(model, usage) {
|
|
1219
|
+
const { promptPerMillion, candidatePerMillion } = geminiRatesFor(model, usage.promptTokens);
|
|
1220
|
+
const m = TOKENS_PER_MILLION;
|
|
1221
|
+
const uncachedPromptTokens = Math.max(0, usage.promptTokens - usage.cachedTokens);
|
|
1222
|
+
const promptCost = uncachedPromptTokens / m * promptPerMillion;
|
|
1223
|
+
const cacheReadCost = usage.cachedTokens / m * promptPerMillion * GEMINI_CACHED_INPUT_MULTIPLIER;
|
|
1224
|
+
const candidateCost = (usage.candidateTokens + usage.thoughtTokens) / m * candidatePerMillion;
|
|
1225
|
+
return {
|
|
1226
|
+
costUsd: promptCost + cacheReadCost + candidateCost,
|
|
1227
|
+
// Implicit caching has no write premium, so this is always >= 0.
|
|
1228
|
+
savedUsd: usage.cachedTokens / m * promptPerMillion - cacheReadCost,
|
|
1229
|
+
breakdown: {
|
|
1230
|
+
promptUsd: promptCost,
|
|
1231
|
+
cacheReadUsd: cacheReadCost,
|
|
1232
|
+
cacheWriteUsd: 0,
|
|
1233
|
+
candidateUsd: candidateCost
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1116
1238
|
// ../../foundation-ai/dist/esm/utils/tool-schema.js
|
|
1117
1239
|
var SCHEMA_MAP_KEYS = ["properties", "patternProperties", "$defs", "definitions"];
|
|
1118
1240
|
var SCHEMA_LIST_KEYS = ["anyOf", "oneOf", "allOf", "prefixItems"];
|
|
@@ -1514,32 +1636,32 @@ function assertSupportedAnthropicModel(model) {
|
|
|
1514
1636
|
throw new Error(`AnthropicTransport: unsupported model "${model}". Use one of: ${SUPPORTED_ANTHROPIC_MODEL_IDS.join(", ")}.`);
|
|
1515
1637
|
}
|
|
1516
1638
|
}
|
|
1517
|
-
function estimatedAnthropicRatesUsdPerMillion(model) {
|
|
1518
|
-
if (model === "claude-haiku-4-5-20251001") {
|
|
1519
|
-
return { promptPerMillion: 1, candidatePerMillion: 5 };
|
|
1520
|
-
}
|
|
1521
|
-
if (model === "claude-fable-5") {
|
|
1522
|
-
return { promptPerMillion: 10, candidatePerMillion: 50 };
|
|
1523
|
-
}
|
|
1524
|
-
if (model === "claude-sonnet-5" || model === "claude-sonnet-4-6") {
|
|
1525
|
-
return { promptPerMillion: 3, candidatePerMillion: 15 };
|
|
1526
|
-
}
|
|
1527
|
-
return { promptPerMillion: 5, candidatePerMillion: 25 };
|
|
1528
|
-
}
|
|
1529
1639
|
function rejectsSamplingParams(model) {
|
|
1530
1640
|
return model === "claude-fable-5" || model === "claude-opus-4-8" || model === "claude-opus-4-7" || model === "claude-sonnet-5";
|
|
1531
1641
|
}
|
|
1532
1642
|
function supportsNativeStructuredOutput(model) {
|
|
1533
1643
|
return model === "claude-fable-5" || model === "claude-opus-4-8" || model === "claude-sonnet-5" || model === "claude-haiku-4-5-20251001";
|
|
1534
1644
|
}
|
|
1535
|
-
function
|
|
1536
|
-
|
|
1537
|
-
return void 0;
|
|
1538
|
-
return { type: "adaptive", display: "summarized" };
|
|
1645
|
+
function supportsAdaptiveThinking(model) {
|
|
1646
|
+
return model !== "claude-haiku-4-5-20251001";
|
|
1539
1647
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1648
|
+
function thinkingIsMandatory(model) {
|
|
1649
|
+
return model === "claude-fable-5";
|
|
1650
|
+
}
|
|
1651
|
+
function anthropicThinking(model, policy) {
|
|
1652
|
+
const defaultsToThinking = model === "claude-sonnet-5" || thinkingIsMandatory(model);
|
|
1653
|
+
const adaptive = { type: "adaptive", display: "summarized" };
|
|
1654
|
+
if (policy === "off") {
|
|
1655
|
+
if (thinkingIsMandatory(model))
|
|
1656
|
+
return adaptive;
|
|
1657
|
+
return defaultsToThinking ? { type: "disabled" } : void 0;
|
|
1658
|
+
}
|
|
1659
|
+
if (policy === "auto") {
|
|
1660
|
+
return supportsAdaptiveThinking(model) ? adaptive : void 0;
|
|
1661
|
+
}
|
|
1662
|
+
return defaultsToThinking ? adaptive : void 0;
|
|
1663
|
+
}
|
|
1664
|
+
var ANTHROPIC_PROVIDER_KEY = "anthropic";
|
|
1543
1665
|
var ResponseTruncatedError = class extends Error {
|
|
1544
1666
|
constructor(model, maxTokens, outputTokens, toolNames) {
|
|
1545
1667
|
super(`Response truncated at ${maxTokens != null ? `the max_tokens cap (${maxTokens})` : "the model's output-token limit"} for model ${model}` + (toolNames.length > 0 ? ` while emitting tool call(s): ${toolNames.join(", ")}` : "") + ". The output exceeds the per-response limit \u2014 raise the provider maxTokens (where configurable) or split the work into smaller outputs.");
|
|
@@ -1551,10 +1673,30 @@ var ResponseTruncatedError = class extends Error {
|
|
|
1551
1673
|
}
|
|
1552
1674
|
};
|
|
1553
1675
|
var AnthropicTransport = class _AnthropicTransport {
|
|
1676
|
+
/**
|
|
1677
|
+
* Warn once when a requested policy is silently clamped, in EITHER direction — which is what
|
|
1678
|
+
* `ChatThinkingPolicy` promises callers. Both directions cost the caller something they asked
|
|
1679
|
+
* for and would otherwise get no signal about: `'off'` on a model that always thinks keeps
|
|
1680
|
+
* billing reasoning as output, and `'auto'` on a model without adaptive support means an agent
|
|
1681
|
+
* that asked to reason quietly does not. (Gemini's twin deliberately stays silent on `'auto'`,
|
|
1682
|
+
* but only because dynamic thinking is already the default there; Haiku defaults to none, so
|
|
1683
|
+
* the same silence would hide a real difference.)
|
|
1684
|
+
*/
|
|
1685
|
+
warnIfThinkingUnclampable(policy) {
|
|
1686
|
+
if (this.warnedThinkingClamped)
|
|
1687
|
+
return;
|
|
1688
|
+
const clamped = policy === "off" && thinkingIsMandatory(this.model) || policy === "auto" && !supportsAdaptiveThinking(this.model);
|
|
1689
|
+
if (!clamped)
|
|
1690
|
+
return;
|
|
1691
|
+
this.warnedThinkingClamped = true;
|
|
1692
|
+
logger.warn(policy === "off" ? `AnthropicTransport: thinkingPolicy 'off' ignored \u2014 ${this.model} always thinks and rejects an explicit disable. Reasoning tokens are still billed as output; switch model if you need them gone.` : `AnthropicTransport: thinkingPolicy 'auto' ignored \u2014 ${this.model} does not support adaptive thinking, so this turn runs without reasoning. Use a Sonnet or Opus tier if the agent needs it.`);
|
|
1693
|
+
}
|
|
1554
1694
|
constructor(config = {}) {
|
|
1555
1695
|
var _a, _b, _c, _d;
|
|
1556
1696
|
this.lifetimeCostUsd = 0;
|
|
1557
1697
|
this.lifetimeSavingsUsd = 0;
|
|
1698
|
+
this.warnedThinkingClamped = false;
|
|
1699
|
+
this.warnedUnknownServingModels = /* @__PURE__ */ new Set();
|
|
1558
1700
|
const model = (_a = config.model) !== null && _a !== void 0 ? _a : DEFAULT_MODEL;
|
|
1559
1701
|
assertSupportedAnthropicModel(model);
|
|
1560
1702
|
this.model = model;
|
|
@@ -1635,8 +1777,12 @@ var AnthropicTransport = class _AnthropicTransport {
|
|
|
1635
1777
|
// ── ChatTransport (multi-turn chat) ────────────────────────────────────
|
|
1636
1778
|
sendChatMessage(history, userMessage, options) {
|
|
1637
1779
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1638
|
-
var _a, _b, _c;
|
|
1639
|
-
const
|
|
1780
|
+
var _a, _b, _c, _d;
|
|
1781
|
+
const reachableModels = /* @__PURE__ */ new Set([
|
|
1782
|
+
this.model,
|
|
1783
|
+
...((_a = options === null || options === void 0 ? void 0 : options.fallbacks) !== null && _a !== void 0 ? _a : []).map((f) => f.model)
|
|
1784
|
+
]);
|
|
1785
|
+
const messages = this.toAnthropicMessages(history, userMessage, options === null || options === void 0 ? void 0 : options.attachments, reachableModels);
|
|
1640
1786
|
const body = {
|
|
1641
1787
|
model: this.model,
|
|
1642
1788
|
max_tokens: this.maxTokens,
|
|
@@ -1644,18 +1790,20 @@ var AnthropicTransport = class _AnthropicTransport {
|
|
|
1644
1790
|
};
|
|
1645
1791
|
if (options === null || options === void 0 ? void 0 : options.systemPrompt)
|
|
1646
1792
|
body.system = options.systemPrompt;
|
|
1647
|
-
if ((
|
|
1793
|
+
if ((_b = options === null || options === void 0 ? void 0 : options.tools) === null || _b === void 0 ? void 0 : _b.length) {
|
|
1648
1794
|
body.tools = options.tools.map((t) => Object.assign({ name: t.name, description: t.description, input_schema: t.enforceSchema ? enforceAnthropicToolSchema(t.parameters, t.name) : t.parameters }, t.enforceSchema ? { strict: true } : {}));
|
|
1649
1795
|
}
|
|
1650
|
-
if ((
|
|
1796
|
+
if ((_c = body.tools) === null || _c === void 0 ? void 0 : _c.length) {
|
|
1651
1797
|
const toolChoice = toAnthropicToolChoice(options === null || options === void 0 ? void 0 : options.toolChoice);
|
|
1652
1798
|
if (toolChoice)
|
|
1653
1799
|
body.tool_choice = toolChoice;
|
|
1654
1800
|
}
|
|
1655
|
-
|
|
1801
|
+
this.warnIfThinkingUnclampable(options === null || options === void 0 ? void 0 : options.thinkingPolicy);
|
|
1802
|
+
const thinking = anthropicThinking(this.model, options === null || options === void 0 ? void 0 : options.thinkingPolicy);
|
|
1656
1803
|
if (thinking)
|
|
1657
1804
|
body.thinking = thinking;
|
|
1658
|
-
|
|
1805
|
+
const thinkingEnabled = (thinking === null || thinking === void 0 ? void 0 : thinking.type) === "adaptive";
|
|
1806
|
+
if ((options === null || options === void 0 ? void 0 : options.temperature) != null && !rejectsSamplingParams(this.model) && !thinkingEnabled) {
|
|
1659
1807
|
body.temperature = scaleTemperature(options.temperature, {
|
|
1660
1808
|
defaultTemp: ANTHROPIC_DEFAULT_TEMPERATURE,
|
|
1661
1809
|
maxTemp: ANTHROPIC_MAX_TEMPERATURE
|
|
@@ -1666,7 +1814,7 @@ var AnthropicTransport = class _AnthropicTransport {
|
|
|
1666
1814
|
format: { type: "json_schema", schema: options.responseSchema }
|
|
1667
1815
|
};
|
|
1668
1816
|
}
|
|
1669
|
-
if ((
|
|
1817
|
+
if ((_d = options === null || options === void 0 ? void 0 : options.fallbacks) === null || _d === void 0 ? void 0 : _d.length) {
|
|
1670
1818
|
body.fallbacks = options.fallbacks.map((f) => f.maxTokens != null ? { model: f.model, max_tokens: f.maxTokens } : { model: f.model });
|
|
1671
1819
|
}
|
|
1672
1820
|
if (options === null || options === void 0 ? void 0 : options.cachePolicy) {
|
|
@@ -1737,31 +1885,27 @@ var AnthropicTransport = class _AnthropicTransport {
|
|
|
1737
1885
|
* and returns the per-call total so the caller can attach it to the response
|
|
1738
1886
|
* message.
|
|
1739
1887
|
*/
|
|
1740
|
-
logTokenUsage(promptTokens, candidateTokens, cacheReadTokens, cacheCreationTokens, cacheCreation1hTokens) {
|
|
1741
|
-
const {
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
this.
|
|
1750
|
-
const cacheReadFull = cacheReadTokens / m * promptPerMillion;
|
|
1751
|
-
const cacheWriteFull = cacheCreationTokens / m * promptPerMillion;
|
|
1752
|
-
const saved = cacheReadFull - cacheReadCost + (cacheWriteFull - cacheWriteCost);
|
|
1753
|
-
this.lifetimeSavingsUsd += saved;
|
|
1888
|
+
logTokenUsage(model, promptTokens, candidateTokens, cacheReadTokens, cacheCreationTokens, cacheCreation1hTokens) {
|
|
1889
|
+
const { costUsd, savedUsd, breakdown } = anthropicTokenCost(model, {
|
|
1890
|
+
uncachedInputTokens: promptTokens,
|
|
1891
|
+
outputTokens: candidateTokens,
|
|
1892
|
+
cacheReadTokens,
|
|
1893
|
+
cacheWriteTokens: cacheCreationTokens,
|
|
1894
|
+
cacheWrite1hTokens: cacheCreation1hTokens
|
|
1895
|
+
});
|
|
1896
|
+
this.lifetimeCostUsd += costUsd;
|
|
1897
|
+
this.lifetimeSavingsUsd += savedUsd;
|
|
1754
1898
|
const dp = _AnthropicTransport.COST_DECIMAL_PLACES;
|
|
1755
|
-
console.log(`--- Anthropic Token Usage (${
|
|
1756
|
-
console.log(`Prompt Tokens: ${promptTokens} ($${
|
|
1757
|
-
console.log(`Cache Read: ${cacheReadTokens} ($${
|
|
1758
|
-
console.log(`Cache Write: ${cacheCreationTokens} ($${
|
|
1759
|
-
console.log(`Candidate Tokens: ${candidateTokens} ($${
|
|
1760
|
-
console.log(`Total Cost: $${
|
|
1761
|
-
console.log(`Cache Saved: $${
|
|
1899
|
+
console.log(`--- Anthropic Token Usage (${model}) ---`);
|
|
1900
|
+
console.log(`Prompt Tokens: ${promptTokens} ($${breakdown.promptUsd.toFixed(dp)})`);
|
|
1901
|
+
console.log(`Cache Read: ${cacheReadTokens} ($${breakdown.cacheReadUsd.toFixed(dp)})`);
|
|
1902
|
+
console.log(`Cache Write: ${cacheCreationTokens} ($${breakdown.cacheWriteUsd.toFixed(dp)})`);
|
|
1903
|
+
console.log(`Candidate Tokens: ${candidateTokens} ($${breakdown.candidateUsd.toFixed(dp)})`);
|
|
1904
|
+
console.log(`Total Cost: $${costUsd.toFixed(dp)}`);
|
|
1905
|
+
console.log(`Cache Saved: $${savedUsd.toFixed(dp)} (lifetime $${this.lifetimeSavingsUsd.toFixed(dp)})`);
|
|
1762
1906
|
console.log(`Lifetime Cost: $${this.lifetimeCostUsd.toFixed(dp)}`);
|
|
1763
1907
|
console.log("--------------------------");
|
|
1764
|
-
return
|
|
1908
|
+
return costUsd;
|
|
1765
1909
|
}
|
|
1766
1910
|
/**
|
|
1767
1911
|
* Convert the internal `ChatMessage[]` history into Anthropic's message format.
|
|
@@ -1772,7 +1916,7 @@ var AnthropicTransport = class _AnthropicTransport {
|
|
|
1772
1916
|
* Consecutive same-role turns are merged by the API but we merge here to keep
|
|
1773
1917
|
* the payload tidy.
|
|
1774
1918
|
*/
|
|
1775
|
-
toAnthropicMessages(history, userMessage, attachments) {
|
|
1919
|
+
toAnthropicMessages(history, userMessage, attachments, reachableModels = /* @__PURE__ */ new Set([this.model])) {
|
|
1776
1920
|
var _a, _b, _c;
|
|
1777
1921
|
const messages = [];
|
|
1778
1922
|
const pushBlock = (role, block) => {
|
|
@@ -1795,6 +1939,9 @@ var AnthropicTransport = class _AnthropicTransport {
|
|
|
1795
1939
|
continue;
|
|
1796
1940
|
}
|
|
1797
1941
|
if ((_a = msg.toolCalls) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1942
|
+
for (const block of this.reasoningToReplay(msg.toolCalls[0], reachableModels)) {
|
|
1943
|
+
pushBlock("assistant", block);
|
|
1944
|
+
}
|
|
1798
1945
|
if (msg.content) {
|
|
1799
1946
|
pushBlock("assistant", { type: "text", text: msg.content });
|
|
1800
1947
|
}
|
|
@@ -1830,20 +1977,140 @@ ${att.content}` });
|
|
|
1830
1977
|
}
|
|
1831
1978
|
return messages;
|
|
1832
1979
|
}
|
|
1980
|
+
/**
|
|
1981
|
+
* The blocks to replay ahead of a tool call — fallback boundaries then reasoning, or none.
|
|
1982
|
+
*
|
|
1983
|
+
* A `signature` is only valid for the model that produced it, so reasoning captured under a
|
|
1984
|
+
* *different* model is normally dropped: an agent that varies `provider` by state can switch
|
|
1985
|
+
* models mid-loop, and replaying the old model's signatures would send blocks the new one
|
|
1986
|
+
* cannot verify.
|
|
1987
|
+
*
|
|
1988
|
+
* Two ways the producer can be the model that will validate:
|
|
1989
|
+
*
|
|
1990
|
+
* 1. **It is the model we are asking for.** `state.model === this.model` — the ordinary case.
|
|
1991
|
+
* 2. **Sticky routing will send this conversation back to it.** After a conversation falls
|
|
1992
|
+
* back, later requests carrying `fallbacks` go straight to the model that served, without
|
|
1993
|
+
* re-running the one that declined. That is what makes a fallback producer's reasoning
|
|
1994
|
+
* replayable at all (Fable 5 configured, Opus 4.8 serving — the pairing this transport's
|
|
1995
|
+
* own constructor warning recommends). But it holds only while the conversation continues
|
|
1996
|
+
* under the SAME request configuration, which is why `requestedModel` is compared rather
|
|
1997
|
+
* than just checking the chain for the producer.
|
|
1998
|
+
*
|
|
1999
|
+
* That second condition is deliberately narrow. Chain membership alone is too weak: a
|
|
2000
|
+
* fallback target is only *contingently* the server, so an agent that switches `provider` to
|
|
2001
|
+
* a model whose own chain happens to contain the old producer would replay foreign
|
|
2002
|
+
* signatures to whichever model actually answers. Requiring the requested model to be
|
|
2003
|
+
* unchanged separates "this conversation is still going" from "we are somewhere else now".
|
|
2004
|
+
*
|
|
2005
|
+
* State captured before `requestedModel` existed falls back to condition 1 alone, which is
|
|
2006
|
+
* the conservative branch — it can drop reasoning, never misdirect it.
|
|
2007
|
+
*
|
|
2008
|
+
* Boundaries themselves are always echoed: keeping them in place is the documented rule, and
|
|
2009
|
+
* with no thinking blocks around them they are inert rather than harmful.
|
|
2010
|
+
*/
|
|
2011
|
+
reasoningToReplay(firstCall, reachableModels) {
|
|
2012
|
+
var _a, _b, _c;
|
|
2013
|
+
const state = (_a = firstCall.providerMetadata) === null || _a === void 0 ? void 0 : _a[ANTHROPIC_PROVIDER_KEY];
|
|
2014
|
+
if (!state)
|
|
2015
|
+
return [];
|
|
2016
|
+
const boundaries = (_b = state.fallbacks) !== null && _b !== void 0 ? _b : [];
|
|
2017
|
+
const stickyToProducer = state.requestedModel === this.model && reachableModels.has(state.model);
|
|
2018
|
+
const vouched = state.model === this.model || stickyToProducer;
|
|
2019
|
+
return [...boundaries, ...vouched ? (_c = state.reasoning) !== null && _c !== void 0 ? _c : [] : []];
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* The model that actually served this response.
|
|
2023
|
+
*
|
|
2024
|
+
* A server-side `fallbacks` chain re-runs a declined request on another model and
|
|
2025
|
+
* names it in the response's top-level `model`. Pricing must follow that, not the
|
|
2026
|
+
* model we asked for: a Fable 5 request served by Opus 4.8 costed at Fable's
|
|
2027
|
+
* $10/$50 instead of $5/$25 doubles that part of the bill.
|
|
2028
|
+
*
|
|
2029
|
+
* An unrecognised model id is NOT priced at a guessed rate — that is precisely how
|
|
2030
|
+
* a consumer ended up billing Haiku at Sonnet rates. It warns and falls back to the
|
|
2031
|
+
* configured model, which is at least a figure someone chose.
|
|
2032
|
+
*/
|
|
2033
|
+
servingModel(response) {
|
|
2034
|
+
const served = response.model;
|
|
2035
|
+
if (!served || served === this.model)
|
|
2036
|
+
return this.model;
|
|
2037
|
+
if (SUPPORTED_ANTHROPIC_MODEL_IDS.includes(served)) {
|
|
2038
|
+
return served;
|
|
2039
|
+
}
|
|
2040
|
+
if (!this.warnedUnknownServingModels.has(served)) {
|
|
2041
|
+
this.warnedUnknownServingModels.add(served);
|
|
2042
|
+
logger.warn(`AnthropicTransport: response was served by "${served}", which is not a known model \u2014 pricing it at the configured "${this.model}" rate instead of guessing. The reported cost for this request may be wrong; add the model to SUPPORTED_ANTHROPIC_MODEL_IDS.`);
|
|
2043
|
+
}
|
|
2044
|
+
return this.model;
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Whether a fallback-chain attempt is a refusal that was **not billed**.
|
|
2048
|
+
*
|
|
2049
|
+
* Anthropic does not charge for a refusal that arrives before any output: the token counts
|
|
2050
|
+
* still appear in `usage`, but they are not on the bill. Pricing them anyway turns the
|
|
2051
|
+
* fallback undercount this reducer was written to fix into an overcount — the documented
|
|
2052
|
+
* example declines with `input_tokens: 535, output_tokens: 0`, which is real money at
|
|
2053
|
+
* Fable 5's prompt rate.
|
|
2054
|
+
*
|
|
2055
|
+
* A **mid-output** refusal *is* billed for the input and whatever it streamed, so output
|
|
2056
|
+
* tokens are the discriminator rather than the refusal itself.
|
|
2057
|
+
*
|
|
2058
|
+
* Declined attempts appear as `type: 'message'`; the attempt that served the turn is
|
|
2059
|
+
* `type: 'fallback_message'`. The serving entry is normally billable — except when every
|
|
2060
|
+
* model in the chain declined, where the last entry is both the serving one and a refusal,
|
|
2061
|
+
* which `lastAndRefused` covers.
|
|
2062
|
+
*
|
|
2063
|
+
* Also called for a response with no chain at all, as `isUnbilledRefusal({}, usage, refused)`:
|
|
2064
|
+
* a direct request that was declined has no `iterations` array, and the same rule applies to
|
|
2065
|
+
* it. That is in fact the common case — `iterations` only appears when `fallbacks` was
|
|
2066
|
+
* configured.
|
|
2067
|
+
*/
|
|
2068
|
+
isUnbilledRefusal(attempt, usage, lastAndRefused) {
|
|
2069
|
+
var _a;
|
|
2070
|
+
if (((_a = usage.output_tokens) !== null && _a !== void 0 ? _a : 0) > 0)
|
|
2071
|
+
return false;
|
|
2072
|
+
return attempt.type === "message" || lastAndRefused;
|
|
2073
|
+
}
|
|
2074
|
+
/** Cost one attempt's usage block at `model`'s rates, logging and banking it. */
|
|
2075
|
+
costAttempt(model, usage) {
|
|
2076
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2077
|
+
const cacheRead = (_a = usage.cache_read_input_tokens) !== null && _a !== void 0 ? _a : 0;
|
|
2078
|
+
const breakdown = usage.cache_creation;
|
|
2079
|
+
const cacheCreation1h = (_b = breakdown === null || breakdown === void 0 ? void 0 : breakdown.ephemeral_1h_input_tokens) !== null && _b !== void 0 ? _b : 0;
|
|
2080
|
+
const cacheCreation = (_c = usage.cache_creation_input_tokens) !== null && _c !== void 0 ? _c : breakdown ? ((_d = breakdown.ephemeral_5m_input_tokens) !== null && _d !== void 0 ? _d : 0) + cacheCreation1h : 0;
|
|
2081
|
+
return this.logTokenUsage(model, (_e = usage.input_tokens) !== null && _e !== void 0 ? _e : 0, (_f = usage.output_tokens) !== null && _f !== void 0 ? _f : 0, cacheRead, cacheCreation, cacheCreation1h);
|
|
2082
|
+
}
|
|
1833
2083
|
fromAnthropicResponse(response) {
|
|
1834
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
2084
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1835
2085
|
let inputTokens;
|
|
1836
2086
|
let outputTokens;
|
|
1837
2087
|
let cacheReadTokens;
|
|
1838
2088
|
let cacheWriteTokens;
|
|
1839
2089
|
let cost;
|
|
2090
|
+
const servingModel = this.servingModel(response);
|
|
1840
2091
|
if (response.usage) {
|
|
1841
2092
|
const uncachedInput = (_a = response.usage.input_tokens) !== null && _a !== void 0 ? _a : 0;
|
|
1842
2093
|
const cacheRead = (_b = response.usage.cache_read_input_tokens) !== null && _b !== void 0 ? _b : 0;
|
|
1843
2094
|
const breakdown = response.usage.cache_creation;
|
|
1844
2095
|
const cacheCreation1h = (_c = breakdown === null || breakdown === void 0 ? void 0 : breakdown.ephemeral_1h_input_tokens) !== null && _c !== void 0 ? _c : 0;
|
|
1845
2096
|
const cacheCreation = (_d = response.usage.cache_creation_input_tokens) !== null && _d !== void 0 ? _d : breakdown ? ((_e = breakdown.ephemeral_5m_input_tokens) !== null && _e !== void 0 ? _e : 0) + cacheCreation1h : 0;
|
|
1846
|
-
|
|
2097
|
+
const attempts = response.usage.iterations;
|
|
2098
|
+
if (attempts === null || attempts === void 0 ? void 0 : attempts.length) {
|
|
2099
|
+
const refused = response.stop_reason === "refusal";
|
|
2100
|
+
cost = attempts.reduce((total, attempt, index) => {
|
|
2101
|
+
var _a2;
|
|
2102
|
+
const usage = (_a2 = attempt.usage) !== null && _a2 !== void 0 ? _a2 : attempt;
|
|
2103
|
+
if (this.isUnbilledRefusal(attempt, usage, index === attempts.length - 1 && refused)) {
|
|
2104
|
+
return total;
|
|
2105
|
+
}
|
|
2106
|
+
const model = attempt.model ? this.servingModel({ model: attempt.model }) : this.model;
|
|
2107
|
+
return total + this.costAttempt(model, usage);
|
|
2108
|
+
}, 0);
|
|
2109
|
+
} else if (this.isUnbilledRefusal({}, response.usage, response.stop_reason === "refusal")) {
|
|
2110
|
+
cost = 0;
|
|
2111
|
+
} else {
|
|
2112
|
+
cost = this.costAttempt(servingModel, response.usage);
|
|
2113
|
+
}
|
|
1847
2114
|
inputTokens = uncachedInput + cacheRead + cacheCreation;
|
|
1848
2115
|
cacheReadTokens = cacheRead;
|
|
1849
2116
|
cacheWriteTokens = cacheCreation;
|
|
@@ -1851,23 +2118,44 @@ ${att.content}` });
|
|
|
1851
2118
|
outputTokens = response.usage.output_tokens;
|
|
1852
2119
|
}
|
|
1853
2120
|
}
|
|
1854
|
-
const blocks = (
|
|
2121
|
+
const blocks = (_f = response.content) !== null && _f !== void 0 ? _f : [];
|
|
1855
2122
|
const toolCalls = [];
|
|
1856
2123
|
const thoughtParts = [];
|
|
1857
2124
|
const textParts = [];
|
|
1858
|
-
|
|
2125
|
+
const reasoningBlocks = [];
|
|
2126
|
+
const fallbackIndex = blocks.map((b) => b.type).lastIndexOf("fallback");
|
|
2127
|
+
const fallbackBlocks = blocks.filter((b) => b.type === "fallback");
|
|
2128
|
+
for (const [index, block] of blocks.entries()) {
|
|
2129
|
+
const postBoundary = index > fallbackIndex;
|
|
1859
2130
|
if (block.type === "tool_use") {
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2131
|
+
if (postBoundary) {
|
|
2132
|
+
toolCalls.push({
|
|
2133
|
+
id: block.id,
|
|
2134
|
+
name: block.name,
|
|
2135
|
+
args: (_g = block.input) !== null && _g !== void 0 ? _g : {}
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
1865
2138
|
} else if (block.type === "thinking") {
|
|
2139
|
+
if (postBoundary)
|
|
2140
|
+
reasoningBlocks.push(block);
|
|
1866
2141
|
thoughtParts.push(block.thinking);
|
|
2142
|
+
} else if (block.type === "redacted_thinking") {
|
|
2143
|
+
if (postBoundary)
|
|
2144
|
+
reasoningBlocks.push(block);
|
|
1867
2145
|
} else if (block.type === "text") {
|
|
1868
2146
|
textParts.push(block.text);
|
|
1869
2147
|
}
|
|
1870
2148
|
}
|
|
2149
|
+
if (toolCalls.length > 0 && (reasoningBlocks.length > 0 || fallbackBlocks.length > 0)) {
|
|
2150
|
+
const state = {
|
|
2151
|
+
reasoning: reasoningBlocks,
|
|
2152
|
+
model: servingModel,
|
|
2153
|
+
requestedModel: this.model
|
|
2154
|
+
};
|
|
2155
|
+
if (fallbackBlocks.length > 0)
|
|
2156
|
+
state.fallbacks = fallbackBlocks;
|
|
2157
|
+
toolCalls[0].providerMetadata = Object.assign(Object.assign({}, toolCalls[0].providerMetadata), { [ANTHROPIC_PROVIDER_KEY]: state });
|
|
2158
|
+
}
|
|
1871
2159
|
if (response.stop_reason === "max_tokens" && toolCalls.length > 0) {
|
|
1872
2160
|
throw new ResponseTruncatedError(this.model, this.maxTokens, outputTokens, toolCalls.map((tc) => tc.name));
|
|
1873
2161
|
}
|
|
@@ -1883,6 +2171,7 @@ ${att.content}` });
|
|
|
1883
2171
|
base.cacheWriteTokens = cacheWriteTokens;
|
|
1884
2172
|
if (cost != null)
|
|
1885
2173
|
base.cost = cost;
|
|
2174
|
+
base.model = servingModel;
|
|
1886
2175
|
if (response.stop_reason === "max_tokens") {
|
|
1887
2176
|
base.responseMeta = { finishReason: "max_tokens" };
|
|
1888
2177
|
}
|
|
@@ -2184,43 +2473,25 @@ function assertSupportedGeminiModel(model) {
|
|
|
2184
2473
|
throw new Error(`GeminiTransport: unsupported model "${model}". Use one of: ${SUPPORTED_GEMINI_MODEL_IDS.join(", ")}.`);
|
|
2185
2474
|
}
|
|
2186
2475
|
}
|
|
2187
|
-
var GEMINI_LONG_CONTEXT_THRESHOLD = 2e5;
|
|
2188
|
-
var GEMINI_CACHED_INPUT_MULTIPLIER = 0.1;
|
|
2189
|
-
var GEMINI_PRICING = {
|
|
2190
|
-
"gemini-2.5-flash-lite": {
|
|
2191
|
-
kind: "flat",
|
|
2192
|
-
rate: { promptPerMillion: 0.1, candidatePerMillion: 0.4 }
|
|
2193
|
-
},
|
|
2194
|
-
"gemini-2.5-flash": { kind: "flat", rate: { promptPerMillion: 0.3, candidatePerMillion: 2.5 } },
|
|
2195
|
-
"gemini-2.5-pro": {
|
|
2196
|
-
kind: "tiered",
|
|
2197
|
-
standard: { promptPerMillion: 1.25, candidatePerMillion: 10 },
|
|
2198
|
-
longContext: { promptPerMillion: 2.5, candidatePerMillion: 15 }
|
|
2199
|
-
},
|
|
2200
|
-
"gemini-3.1-flash-lite": {
|
|
2201
|
-
kind: "flat",
|
|
2202
|
-
rate: { promptPerMillion: 0.25, candidatePerMillion: 1.5 }
|
|
2203
|
-
},
|
|
2204
|
-
"gemini-3.5-flash": { kind: "flat", rate: { promptPerMillion: 1.5, candidatePerMillion: 9 } },
|
|
2205
|
-
"gemini-3.1-pro-preview": {
|
|
2206
|
-
kind: "tiered",
|
|
2207
|
-
standard: { promptPerMillion: 2, candidatePerMillion: 12 },
|
|
2208
|
-
longContext: { promptPerMillion: 4, candidatePerMillion: 18 }
|
|
2209
|
-
}
|
|
2210
|
-
};
|
|
2211
|
-
function estimatedGeminiPaidRatesUsdPerMillion(model, promptTokens) {
|
|
2212
|
-
const pricing = GEMINI_PRICING[model];
|
|
2213
|
-
if (pricing.kind === "flat") {
|
|
2214
|
-
return pricing.rate;
|
|
2215
|
-
}
|
|
2216
|
-
return promptTokens > GEMINI_LONG_CONTEXT_THRESHOLD ? pricing.longContext : pricing.standard;
|
|
2217
|
-
}
|
|
2218
2476
|
var GEMINI_MODEL_WARNINGS = {
|
|
2219
2477
|
"gemini-2.5-flash": "GeminiTransport: using gemini-2.5-flash \u2014 higher cost than flash-lite; use for harder reasoning or agent tasks.",
|
|
2220
2478
|
"gemini-2.5-pro": "GeminiTransport: using gemini-2.5-pro \u2014 significantly higher, prompt-size-tiered cost; reserve for tasks where flash reliability is insufficient.",
|
|
2221
2479
|
"gemini-3.5-flash": "GeminiTransport: using gemini-3.5-flash \u2014 frontier model, materially higher cost than flash-lite; use for harder reasoning or agent tasks.",
|
|
2222
2480
|
"gemini-3.1-pro-preview": "GeminiTransport: using gemini-3.1-pro-preview \u2014 PREVIEW model (no stability guarantee, may be withdrawn) with significantly higher, prompt-size-tiered cost; reserve for tasks where flash reliability is insufficient."
|
|
2223
2481
|
};
|
|
2482
|
+
var GEMINI_THINKING_DISABLEABLE = [
|
|
2483
|
+
"gemini-2.5-flash",
|
|
2484
|
+
"gemini-2.5-flash-lite"
|
|
2485
|
+
];
|
|
2486
|
+
function geminiThinkingConfig(model, policy) {
|
|
2487
|
+
if (policy === "off" && GEMINI_THINKING_DISABLEABLE.includes(model)) {
|
|
2488
|
+
return { includeThoughts: false, thinkingBudget: 0 };
|
|
2489
|
+
}
|
|
2490
|
+
if (policy === "auto" && GEMINI_THINKING_DISABLEABLE.includes(model)) {
|
|
2491
|
+
return { includeThoughts: true, thinkingBudget: -1 };
|
|
2492
|
+
}
|
|
2493
|
+
return { includeThoughts: true };
|
|
2494
|
+
}
|
|
2224
2495
|
var SKIP_SIGNATURE = "skip_thought_signature_validator";
|
|
2225
2496
|
var GEMINI_PROVIDER_KEY = "gemini";
|
|
2226
2497
|
var MalformedFunctionCallError = class extends Error {
|
|
@@ -2231,10 +2502,28 @@ var MalformedFunctionCallError = class extends Error {
|
|
|
2231
2502
|
}
|
|
2232
2503
|
};
|
|
2233
2504
|
var GeminiTransport = class _GeminiTransport {
|
|
2505
|
+
/**
|
|
2506
|
+
* Warn once when a requested policy is silently clamped. Turning thinking off is a *cost*
|
|
2507
|
+
* decision, so a caller who asked for it and kept paying for reasoning tokens needs to hear
|
|
2508
|
+
* about it — but only once, not per turn.
|
|
2509
|
+
*
|
|
2510
|
+
* Only `'off'` can actually be denied. `'auto'` is already what an omitted budget produces on
|
|
2511
|
+
* every model here — dynamic thinking is the documented default — so warning that it was
|
|
2512
|
+
* "ignored" would be false, and latching on it would spend the one warning the genuinely
|
|
2513
|
+
* unhonourable `'off'` needs.
|
|
2514
|
+
*/
|
|
2515
|
+
warnIfThinkingUnclampable(policy) {
|
|
2516
|
+
if (policy !== "off" || GEMINI_THINKING_DISABLEABLE.includes(this.model) || this.warnedThinkingClamped) {
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2519
|
+
this.warnedThinkingClamped = true;
|
|
2520
|
+
logger.warn(`GeminiTransport: thinkingPolicy 'off' ignored \u2014 ${this.model} runs its default thinking posture and takes no budget we can safely set. Reasoning tokens are still billed at the candidate rate; use a flash tier if you need them gone.`);
|
|
2521
|
+
}
|
|
2234
2522
|
constructor(config = {}) {
|
|
2235
2523
|
var _a, _b, _c;
|
|
2236
2524
|
this.lifetimeCostUsd = 0;
|
|
2237
2525
|
this.lifetimeSavingsUsd = 0;
|
|
2526
|
+
this.warnedThinkingClamped = false;
|
|
2238
2527
|
const model = (_a = config.model) !== null && _a !== void 0 ? _a : DEFAULT_MODEL2;
|
|
2239
2528
|
assertSupportedGeminiModel(model);
|
|
2240
2529
|
this.model = model;
|
|
@@ -2301,7 +2590,8 @@ var GeminiTransport = class _GeminiTransport {
|
|
|
2301
2590
|
] : void 0;
|
|
2302
2591
|
const systemInstruction = (options === null || options === void 0 ? void 0 : options.systemPrompt) ? { role: "system", parts: [{ text: options.systemPrompt }] } : void 0;
|
|
2303
2592
|
const toolConfig = tools ? toGeminiToolConfig(options === null || options === void 0 ? void 0 : options.toolChoice) : void 0;
|
|
2304
|
-
|
|
2593
|
+
this.warnIfThinkingUnclampable(options === null || options === void 0 ? void 0 : options.thinkingPolicy);
|
|
2594
|
+
const generationConfig = { thinkingConfig: geminiThinkingConfig(this.model, options === null || options === void 0 ? void 0 : options.thinkingPolicy) };
|
|
2305
2595
|
if ((options === null || options === void 0 ? void 0 : options.temperature) != null) {
|
|
2306
2596
|
generationConfig.temperature = scaleTemperature(options.temperature, {
|
|
2307
2597
|
defaultTemp: GEMINI_DEFAULT_TEMPERATURE,
|
|
@@ -2328,25 +2618,23 @@ var GeminiTransport = class _GeminiTransport {
|
|
|
2328
2618
|
* message.
|
|
2329
2619
|
*/
|
|
2330
2620
|
logTokenUsage(promptTokens, candidateTokens, thoughtTokens, cachedTokens) {
|
|
2331
|
-
const {
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
this.
|
|
2339
|
-
const saved = cachedTokens / m * promptPerMillion - cacheReadCost;
|
|
2340
|
-
this.lifetimeSavingsUsd += saved;
|
|
2621
|
+
const { costUsd, savedUsd, breakdown } = geminiTokenCost(this.model, {
|
|
2622
|
+
promptTokens,
|
|
2623
|
+
candidateTokens,
|
|
2624
|
+
thoughtTokens,
|
|
2625
|
+
cachedTokens
|
|
2626
|
+
});
|
|
2627
|
+
this.lifetimeCostUsd += costUsd;
|
|
2628
|
+
this.lifetimeSavingsUsd += savedUsd;
|
|
2341
2629
|
const dp = _GeminiTransport.COST_DECIMAL_PLACES;
|
|
2342
2630
|
console.log(`--- Gemini Token Usage (${this.model}) ---`);
|
|
2343
|
-
console.log(`Prompt Tokens: ${promptTokens} (${cachedTokens} cached) ($${
|
|
2344
|
-
console.log(`Candidate Tokens: ${candidateTokens} (+${thoughtTokens} thinking) ($${
|
|
2345
|
-
console.log(`Total Cost: $${
|
|
2346
|
-
console.log(`Cache Saved: $${
|
|
2631
|
+
console.log(`Prompt Tokens: ${promptTokens} (${cachedTokens} cached) ($${breakdown.promptUsd.toFixed(dp)} + $${breakdown.cacheReadUsd.toFixed(dp)})`);
|
|
2632
|
+
console.log(`Candidate Tokens: ${candidateTokens} (+${thoughtTokens} thinking) ($${breakdown.candidateUsd.toFixed(dp)})`);
|
|
2633
|
+
console.log(`Total Cost: $${costUsd.toFixed(dp)}`);
|
|
2634
|
+
console.log(`Cache Saved: $${savedUsd.toFixed(dp)} (lifetime $${this.lifetimeSavingsUsd.toFixed(dp)})`);
|
|
2347
2635
|
console.log(`Lifetime Cost: $${this.lifetimeCostUsd.toFixed(dp)}`);
|
|
2348
2636
|
console.log("--------------------------");
|
|
2349
|
-
return
|
|
2637
|
+
return costUsd;
|
|
2350
2638
|
}
|
|
2351
2639
|
toGeminiContents(history, userMessage, attachments) {
|
|
2352
2640
|
var _a, _b, _c;
|
|
@@ -3317,6 +3605,18 @@ function emptyUsage() {
|
|
|
3317
3605
|
outputTokens: 0
|
|
3318
3606
|
};
|
|
3319
3607
|
}
|
|
3608
|
+
function totalTokens(usage) {
|
|
3609
|
+
return usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens + usage.outputTokens;
|
|
3610
|
+
}
|
|
3611
|
+
function addUsage(a, b) {
|
|
3612
|
+
return {
|
|
3613
|
+
costUsd: a.costUsd + b.costUsd,
|
|
3614
|
+
uncachedInputTokens: a.uncachedInputTokens + b.uncachedInputTokens,
|
|
3615
|
+
cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,
|
|
3616
|
+
cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens,
|
|
3617
|
+
outputTokens: a.outputTokens + b.outputTokens
|
|
3618
|
+
};
|
|
3619
|
+
}
|
|
3320
3620
|
function sumUsage(messages) {
|
|
3321
3621
|
const total = emptyUsage();
|
|
3322
3622
|
accumulate(messages, total);
|
|
@@ -3805,6 +4105,7 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3805
4105
|
this.activeTemperatureInput = config.temperature;
|
|
3806
4106
|
this.activeToolChoiceInput = config.toolChoice;
|
|
3807
4107
|
this.activeCachePolicyInput = config.cachePolicy;
|
|
4108
|
+
this.activeThinkingPolicyInput = config.thinkingPolicy;
|
|
3808
4109
|
this.activeTailContextInput = config.tailContext;
|
|
3809
4110
|
this.activeResponseSchemaInput = config.responseSchema;
|
|
3810
4111
|
this.activeFallbacks = config.fallbacks;
|
|
@@ -4459,16 +4760,27 @@ Output format (strict):
|
|
|
4459
4760
|
* `condenseWhen` can register against the right call (it stamps the clocks
|
|
4460
4761
|
* straight off the driver). Absent for dispatch paths with no addressable tool
|
|
4461
4762
|
* call (e.g. the fold-close handler), where `condenseWhen` is a no-op.
|
|
4462
|
-
* @param traceCapture - Optional per-
|
|
4463
|
-
*
|
|
4464
|
-
* so parallel tool calls each capture their own
|
|
4763
|
+
* @param traceCapture - Optional per-tool-call accumulator. When provided, every
|
|
4764
|
+
* sub-agent call's trace is **appended** here rather than written to shared
|
|
4765
|
+
* instance state, so parallel tool calls each capture their own traces
|
|
4766
|
+
* independently.
|
|
4767
|
+
*
|
|
4768
|
+
* Deliberately a list of traces, not one slot. A single handler may call
|
|
4769
|
+
* `requestSubAgent` more than once — a code-driven scheduler dispatching a
|
|
4770
|
+
* dependency graph, a retry of a timed-out child, any fan-out helper — and a
|
|
4771
|
+
* single slot kept only the last, so every other child ran, was billed by the
|
|
4772
|
+
* provider, and then vanished from history. The loss was silent in the worst
|
|
4773
|
+
* way: `sumUsage` and `usageRows` both recurse into the trace, so they summed a
|
|
4774
|
+
* truncated input and still agreed with each other. Measured at 1 of 7 traces
|
|
4775
|
+
* kept on a seven-way fan-out, reporting ~2.3x under the real cost, with the
|
|
4776
|
+
* error growing as the fan-out widens.
|
|
4465
4777
|
*/
|
|
4466
4778
|
buildHandlerContext(activeToolCallId, traceCapture) {
|
|
4467
4779
|
return {
|
|
4468
4780
|
requestInteraction: (componentName, data, options) => this.requestInteraction(componentName, data, options),
|
|
4469
4781
|
...this.subAgentsMap.size > 0 && {
|
|
4470
4782
|
requestSubAgent: (name, options) => this.invokeSubAgent(name, options).then(({ outcome, trace }) => {
|
|
4471
|
-
if (traceCapture) traceCapture.trace
|
|
4783
|
+
if (traceCapture && trace) traceCapture.traces.push(trace);
|
|
4472
4784
|
return outcome;
|
|
4473
4785
|
})
|
|
4474
4786
|
},
|
|
@@ -4842,6 +5154,8 @@ Output format (strict):
|
|
|
4842
5154
|
let emptyResponseAttempts = 0;
|
|
4843
5155
|
let setupTransportAttempts = 0;
|
|
4844
5156
|
let firstLlmCall = !!currentInput;
|
|
5157
|
+
let pinnedThinkingPolicy;
|
|
5158
|
+
let thinkingPolicyPinned = false;
|
|
4845
5159
|
while (iterations < this.maxToolIterations) {
|
|
4846
5160
|
iterations += 1;
|
|
4847
5161
|
this.modelCallSeq += 1;
|
|
@@ -4941,7 +5255,8 @@ Output format (strict):
|
|
|
4941
5255
|
resolvedToolChoice,
|
|
4942
5256
|
resolvedCachePolicy,
|
|
4943
5257
|
resolvedTailContext,
|
|
4944
|
-
resolvedResponseSchema
|
|
5258
|
+
resolvedResponseSchema,
|
|
5259
|
+
firstResolvedThinkingPolicy
|
|
4945
5260
|
] = (
|
|
4946
5261
|
// oxlint-disable-next-line no-await-in-loop
|
|
4947
5262
|
await Promise.all([
|
|
@@ -4949,9 +5264,19 @@ Output format (strict):
|
|
|
4949
5264
|
this.resolveTurnInput(this.activeToolChoiceInput, promptCtx),
|
|
4950
5265
|
this.resolveTurnInput(this.activeCachePolicyInput, promptCtx),
|
|
4951
5266
|
this.resolveTurnInput(this.activeTailContextInput, promptCtx),
|
|
4952
|
-
this.resolveTurnInput(this.activeResponseSchemaInput, promptCtx)
|
|
5267
|
+
this.resolveTurnInput(this.activeResponseSchemaInput, promptCtx),
|
|
5268
|
+
// Only consulted on the first iteration (see `pinnedThinkingPolicy`); resolved
|
|
5269
|
+
// alongside the others so a resolver still sees the same turn context.
|
|
5270
|
+
thinkingPolicyPinned ? Promise.resolve(void 0) : this.resolveTurnInput(
|
|
5271
|
+
this.activeThinkingPolicyInput,
|
|
5272
|
+
promptCtx
|
|
5273
|
+
)
|
|
4953
5274
|
])
|
|
4954
5275
|
);
|
|
5276
|
+
if (!thinkingPolicyPinned) {
|
|
5277
|
+
pinnedThinkingPolicy = firstResolvedThinkingPolicy;
|
|
5278
|
+
thinkingPolicyPinned = true;
|
|
5279
|
+
}
|
|
4955
5280
|
const systemPrompt = resolvedSystemPrompt || void 0;
|
|
4956
5281
|
const tailBody = [resolvedTailContext, frameworkSystemSuffix].map((part) => (part ?? "").trim()).filter((part) => part.length > 0).join("\n\n");
|
|
4957
5282
|
const tailContext = tailBody ? `<system-reminder>
|
|
@@ -4978,6 +5303,12 @@ ${tailBody}
|
|
|
4978
5303
|
// Prompt-cache policy for this turn (Anthropic places breakpoints per scope; Gemini
|
|
4979
5304
|
// caches implicitly regardless). Undefined → no caching requested.
|
|
4980
5305
|
cachePolicy: resolvedCachePolicy,
|
|
5306
|
+
// Extended-thinking posture, pinned for the whole tool loop (one assistant turn) rather
|
|
5307
|
+
// than re-resolved per iteration — see `pinnedThinkingPolicy`. Undefined — unset, or the
|
|
5308
|
+
// resolver's answer for this turn — is NOT "off": it leaves the model on its own default,
|
|
5309
|
+
// so agents that never set this are priced exactly as before. Transports clamp models
|
|
5310
|
+
// that can't honour it.
|
|
5311
|
+
thinkingPolicy: pinnedThinkingPolicy,
|
|
4981
5312
|
// Framed volatile context injected at the message tail (never stored). Undefined → none.
|
|
4982
5313
|
tailContext,
|
|
4983
5314
|
// Structured-output schema for this turn (agent/state-resolved). When set, the transport
|
|
@@ -5098,7 +5429,9 @@ ${tailBody}
|
|
|
5098
5429
|
}
|
|
5099
5430
|
throw e;
|
|
5100
5431
|
}
|
|
5101
|
-
if (this.lastResolvedModel !== void 0)
|
|
5432
|
+
if (response.model === void 0 && this.lastResolvedModel !== void 0) {
|
|
5433
|
+
response.model = this.lastResolvedModel;
|
|
5434
|
+
}
|
|
5102
5435
|
if (this.lastResolvedProvider !== void 0) response.provider = this.lastResolvedProvider;
|
|
5103
5436
|
if (this.lastResolvedProviderName !== void 0) {
|
|
5104
5437
|
response.providerName = this.lastResolvedProviderName;
|
|
@@ -5306,14 +5639,18 @@ ${tailBody}
|
|
|
5306
5639
|
}
|
|
5307
5640
|
return;
|
|
5308
5641
|
}
|
|
5642
|
+
const traceCapture = { traces: [] };
|
|
5643
|
+
const capturedTrace = () => traceCapture.traces.length ? traceCapture.traces.flat() : void 0;
|
|
5309
5644
|
try {
|
|
5310
|
-
const traceCapture = {};
|
|
5311
5645
|
const result = await handler(tc.args, this.buildHandlerContext(tc.id, traceCapture));
|
|
5312
5646
|
const content = typeof result === "string" ? result : JSON.stringify(result);
|
|
5313
5647
|
executedById.set(tc.id, {
|
|
5314
5648
|
toolCallId: tc.id,
|
|
5315
5649
|
content,
|
|
5316
|
-
|
|
5650
|
+
// Concatenated when a handler invoked several children, so none is lost.
|
|
5651
|
+
// Stays `undefined` when nothing was captured — readers key off presence,
|
|
5652
|
+
// and an empty array is a different claim from "no sub-agent ran".
|
|
5653
|
+
subAgentTrace: capturedTrace()
|
|
5317
5654
|
});
|
|
5318
5655
|
anyRealToolExecuted = true;
|
|
5319
5656
|
} catch (e) {
|
|
@@ -5328,7 +5665,10 @@ ${tailBody}
|
|
|
5328
5665
|
// Structured recovery hint so the model retries or routes around a tool
|
|
5329
5666
|
// failure instead of apologising and giving up.
|
|
5330
5667
|
content: `Tool error: ${e.message}
|
|
5331
|
-
RECOVERY: this tool failed once \u2014 you may retry it, or take a different valid action to make progress. Do NOT abandon the task, ask the user to rephrase, or claim you cannot make changes. If a planning tool failed, retry it or proceed with the information you already have
|
|
5668
|
+
RECOVERY: this tool failed once \u2014 you may retry it, or take a different valid action to make progress. Do NOT abandon the task, ask the user to rephrase, or claim you cannot make changes. If a planning tool failed, retry it or proceed with the information you already have.`,
|
|
5669
|
+
// Children that completed before the throw were still billed — keep
|
|
5670
|
+
// their traces so the run's cost stays whole.
|
|
5671
|
+
subAgentTrace: capturedTrace()
|
|
5332
5672
|
});
|
|
5333
5673
|
anyRealToolExecuted = true;
|
|
5334
5674
|
}
|
|
@@ -6120,6 +6460,10 @@ function defineStatefulAgent(opts) {
|
|
|
6120
6460
|
}
|
|
6121
6461
|
return opts.cachePolicy({ ...ctx, state });
|
|
6122
6462
|
} : opts.cachePolicy;
|
|
6463
|
+
const wrappedThinkingPolicy = typeof opts.thinkingPolicy === "function" ? async (ctx) => {
|
|
6464
|
+
if (!state) return void 0;
|
|
6465
|
+
return opts.thinkingPolicy({ ...ctx, state });
|
|
6466
|
+
} : opts.thinkingPolicy;
|
|
6123
6467
|
const wrappedTailContext = typeof opts.tailContext === "function" ? async (ctx) => {
|
|
6124
6468
|
if (!state) {
|
|
6125
6469
|
throw new Error(`Stateful agent "${opts.name}" tailContext called before init`);
|
|
@@ -6158,6 +6502,7 @@ function defineStatefulAgent(opts) {
|
|
|
6158
6502
|
temperature: wrappedTemperature,
|
|
6159
6503
|
toolChoice: wrappedToolChoice,
|
|
6160
6504
|
cachePolicy: wrappedCachePolicy,
|
|
6505
|
+
thinkingPolicy: wrappedThinkingPolicy,
|
|
6161
6506
|
tailContext: wrappedTailContext,
|
|
6162
6507
|
onUnresolvedTool: wrappedOnUnresolvedTool,
|
|
6163
6508
|
resumable: wrappedResumable,
|
|
@@ -6219,6 +6564,69 @@ var strictFallbackAgent = {
|
|
|
6219
6564
|
systemPrompt: `You are a concise assistant. The user's request is outside your scope. Respond with a single short sentence stating what you can assist with. Do not elaborate. The available specialists are: {{agents}}.`
|
|
6220
6565
|
};
|
|
6221
6566
|
|
|
6567
|
+
// src/utils/usage-rows.ts
|
|
6568
|
+
function hasUsage(m) {
|
|
6569
|
+
return m.cost != null || m.externalCostUsd != null || m.inputTokens != null || m.outputTokens != null || m.cacheReadTokens != null || m.cacheWriteTokens != null;
|
|
6570
|
+
}
|
|
6571
|
+
function usageRows(messages) {
|
|
6572
|
+
return collectRows(messages, 0, void 0);
|
|
6573
|
+
}
|
|
6574
|
+
function bucketsOf(usage) {
|
|
6575
|
+
return {
|
|
6576
|
+
uncachedInputTokens: usage.uncachedInputTokens,
|
|
6577
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
6578
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
6579
|
+
outputTokens: usage.outputTokens
|
|
6580
|
+
};
|
|
6581
|
+
}
|
|
6582
|
+
function collectRows(messages, depth, subAgentOf) {
|
|
6583
|
+
const rows = [];
|
|
6584
|
+
for (const m of messages) {
|
|
6585
|
+
if (hasUsage(m)) {
|
|
6586
|
+
const cacheReadTokens = m.cacheReadTokens ?? 0;
|
|
6587
|
+
const cacheWriteTokens = m.cacheWriteTokens ?? 0;
|
|
6588
|
+
rows.push({
|
|
6589
|
+
source: "request",
|
|
6590
|
+
model: m.model,
|
|
6591
|
+
// The driver stamps `ChatMessage.provider` from the resolved provider's own
|
|
6592
|
+
// status, so it is AUTHORITATIVE and covers vendors the model allowlists do
|
|
6593
|
+
// not — a server-proxied `gpt-5` turn is `provider: 'openai'` on the message
|
|
6594
|
+
// and unknown to `vendorOfModel`. Prefer it; fall back to resolving the model
|
|
6595
|
+
// id only for messages persisted before the field existed. Still left
|
|
6596
|
+
// undefined when neither knows, rather than guessed at.
|
|
6597
|
+
provider: m.provider ?? (m.model ? vendorOfModel(m.model) : void 0),
|
|
6598
|
+
...m.cost != null && { costUsd: m.cost },
|
|
6599
|
+
...m.externalCostUsd != null && { externalCostUsd: m.externalCostUsd },
|
|
6600
|
+
// Uncached input is the REMAINDER, matching `sumUsage`: `inputTokens` is the
|
|
6601
|
+
// whole prompt and the cache fields break it down. Clamped for the same
|
|
6602
|
+
// reason — hand-edited history must not drive a total negative.
|
|
6603
|
+
uncachedInputTokens: Math.max(0, (m.inputTokens ?? 0) - cacheReadTokens - cacheWriteTokens),
|
|
6604
|
+
cacheReadTokens,
|
|
6605
|
+
cacheWriteTokens,
|
|
6606
|
+
outputTokens: m.outputTokens ?? 0,
|
|
6607
|
+
...m.agentName != null && { agentName: m.agentName },
|
|
6608
|
+
subAgentDepth: depth,
|
|
6609
|
+
...subAgentOf != null && { subAgentOf }
|
|
6610
|
+
});
|
|
6611
|
+
}
|
|
6612
|
+
const rolled = m.compaction?.rolledUpUsage;
|
|
6613
|
+
if (rolled) {
|
|
6614
|
+
rows.push({
|
|
6615
|
+
source: "compaction",
|
|
6616
|
+
...rolled.costUsd != null && { costUsd: rolled.costUsd },
|
|
6617
|
+
...bucketsOf(rolled),
|
|
6618
|
+
...m.agentName != null && { agentName: m.agentName },
|
|
6619
|
+
subAgentDepth: depth,
|
|
6620
|
+
...subAgentOf != null && { subAgentOf }
|
|
6621
|
+
});
|
|
6622
|
+
}
|
|
6623
|
+
for (const tc of m.toolCalls ?? []) {
|
|
6624
|
+
if (tc.subAgentTrace) rows.push(...collectRows(tc.subAgentTrace, depth + 1, tc.id));
|
|
6625
|
+
}
|
|
6626
|
+
}
|
|
6627
|
+
return rows;
|
|
6628
|
+
}
|
|
6629
|
+
|
|
6222
6630
|
// src/utils/flatten-sub-agent-messages.ts
|
|
6223
6631
|
function flattenSubAgentMessages(messages, prefix = "", depth = 0, subAgentOf) {
|
|
6224
6632
|
return messages.flatMap((m) => {
|
|
@@ -6300,10 +6708,15 @@ function assembleDebugLog(entries, readme) {
|
|
|
6300
6708
|
}
|
|
6301
6709
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6302
6710
|
0 && (module.exports = {
|
|
6711
|
+
ANTHROPIC_CACHE_READ_MULTIPLIER,
|
|
6712
|
+
ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER,
|
|
6713
|
+
ANTHROPIC_CACHE_WRITE_5M_MULTIPLIER,
|
|
6303
6714
|
AgenticActivityBus,
|
|
6304
6715
|
AnthropicProvider,
|
|
6305
6716
|
AnthropicTransport,
|
|
6306
6717
|
ChatDriver,
|
|
6718
|
+
GEMINI_CACHED_INPUT_MULTIPLIER,
|
|
6719
|
+
GEMINI_LONG_CONTEXT_THRESHOLD,
|
|
6307
6720
|
GeminiProvider,
|
|
6308
6721
|
GeminiTransport,
|
|
6309
6722
|
MutableAIProviderRegistry,
|
|
@@ -6312,16 +6725,26 @@ function assembleDebugLog(entries, readme) {
|
|
|
6312
6725
|
REQUEST_CONTINUATION_TOOL,
|
|
6313
6726
|
SUPPORTED_ANTHROPIC_MODEL_IDS,
|
|
6314
6727
|
SUPPORTED_GEMINI_MODEL_IDS,
|
|
6728
|
+
addUsage,
|
|
6315
6729
|
agenticActivityBus,
|
|
6730
|
+
anthropicRatesFor,
|
|
6731
|
+
anthropicTokenCost,
|
|
6316
6732
|
assembleDebugLog,
|
|
6317
6733
|
buildTimelineEntries,
|
|
6318
6734
|
clearSession,
|
|
6319
6735
|
defineAgent,
|
|
6320
6736
|
defineStatefulAgent,
|
|
6737
|
+
emptyUsage,
|
|
6321
6738
|
friendlyFallbackAgent,
|
|
6739
|
+
geminiRatesFor,
|
|
6740
|
+
geminiTokenCost,
|
|
6322
6741
|
getMetaEvents,
|
|
6323
6742
|
isObservableAIProviderRegistry,
|
|
6324
6743
|
restoreMachine,
|
|
6325
|
-
strictFallbackAgent
|
|
6744
|
+
strictFallbackAgent,
|
|
6745
|
+
sumUsage,
|
|
6746
|
+
totalTokens,
|
|
6747
|
+
usageRows,
|
|
6748
|
+
vendorOfModel
|
|
6326
6749
|
});
|
|
6327
6750
|
//# sourceMappingURL=chat-driver.cjs.map
|