@genesislcap/ai-assistant 15.4.1 → 15.5.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.
Files changed (91) hide show
  1. package/dist/ai-assistant.api.json +544 -82
  2. package/dist/ai-assistant.d.ts +324 -36
  3. package/dist/chat-driver.cjs +94 -22
  4. package/dist/chat-driver.cjs.map +3 -3
  5. package/dist/chat-driver.mjs +94 -22
  6. package/dist/chat-driver.mjs.map +3 -3
  7. package/dist/custom-elements.json +303 -36
  8. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  9. package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
  10. package/dist/dts/components/settings-modal/settings-modal.template.d.ts +9 -2
  11. package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
  12. package/dist/dts/index.d.ts +1 -0
  13. package/dist/dts/index.d.ts.map +1 -1
  14. package/dist/dts/main/cost-session-banking.test.d.ts +2 -0
  15. package/dist/dts/main/cost-session-banking.test.d.ts.map +1 -0
  16. package/dist/dts/main/main.d.ts +184 -24
  17. package/dist/dts/main/main.d.ts.map +1 -1
  18. package/dist/dts/provider/assistant-app-settings.d.ts +30 -5
  19. package/dist/dts/provider/assistant-app-settings.d.ts.map +1 -1
  20. package/dist/dts/state/ai-assistant-slice.d.ts +11 -8
  21. package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
  22. package/dist/dts/state/persistence/session-persistence-provider.d.ts +23 -0
  23. package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -1
  24. package/dist/dts/state/persistence/session-snapshot.d.ts.map +1 -1
  25. package/dist/dts/state/session-store.d.ts +1 -2
  26. package/dist/dts/state/session-store.d.ts.map +1 -1
  27. package/dist/dts/styles/settings-section.d.ts +29 -0
  28. package/dist/dts/styles/settings-section.d.ts.map +1 -0
  29. package/dist/dts/utils/cost-session-history.d.ts +103 -12
  30. package/dist/dts/utils/cost-session-history.d.ts.map +1 -1
  31. package/dist/dts/utils/resolve-cost-history-config.d.ts +9 -3
  32. package/dist/dts/utils/resolve-cost-history-config.d.ts.map +1 -1
  33. package/dist/dts/utils/sum-costs.d.ts.map +1 -1
  34. package/dist/dts/utils/sum-tokens.d.ts +8 -8
  35. package/dist/dts/utils/sum-tokens.d.ts.map +1 -1
  36. package/dist/dts/utils/sum-usage.d.ts +59 -0
  37. package/dist/dts/utils/sum-usage.d.ts.map +1 -0
  38. package/dist/dts/utils/sum-usage.test.d.ts +2 -0
  39. package/dist/dts/utils/sum-usage.test.d.ts.map +1 -0
  40. package/dist/esm/components/chat-driver/chat-driver.js +6 -0
  41. package/dist/esm/components/settings-modal/settings-modal.styles.js +237 -18
  42. package/dist/esm/components/settings-modal/settings-modal.template.js +229 -73
  43. package/dist/esm/index.js +1 -0
  44. package/dist/esm/main/cost-session-banking.test.js +308 -0
  45. package/dist/esm/main/main.js +424 -71
  46. package/dist/esm/state/ai-assistant-slice.js +11 -8
  47. package/dist/esm/state/ai-assistant-slice.test.js +12 -5
  48. package/dist/esm/state/debug-event-log.js +2 -2
  49. package/dist/esm/state/persistence/session-persistence.integration.test.js +5 -1
  50. package/dist/esm/state/persistence/session-persister.js +2 -2
  51. package/dist/esm/state/persistence/session-persister.test.js +10 -1
  52. package/dist/esm/state/persistence/session-snapshot.js +6 -2
  53. package/dist/esm/state/persistence/session-snapshot.test.js +4 -1
  54. package/dist/esm/state/persistence/stateful-restore.e2e.test.js +10 -1
  55. package/dist/esm/styles/settings-section.js +39 -0
  56. package/dist/esm/utils/cost-session-history.js +92 -15
  57. package/dist/esm/utils/cost-session-history.test.js +155 -13
  58. package/dist/esm/utils/resolve-cost-history-config.js +2 -1
  59. package/dist/esm/utils/sum-costs.js +2 -13
  60. package/dist/esm/utils/sum-tokens.js +10 -27
  61. package/dist/esm/utils/sum-tokens.test.js +1 -5
  62. package/dist/esm/utils/sum-usage.js +123 -0
  63. package/dist/esm/utils/sum-usage.test.js +120 -0
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +17 -17
  66. package/src/components/chat-driver/chat-driver.ts +6 -0
  67. package/src/components/settings-modal/settings-modal.styles.ts +237 -18
  68. package/src/components/settings-modal/settings-modal.template.ts +270 -81
  69. package/src/index.ts +1 -0
  70. package/src/main/cost-session-banking.test.ts +407 -0
  71. package/src/main/main.ts +433 -68
  72. package/src/provider/assistant-app-settings.ts +31 -5
  73. package/src/state/ai-assistant-slice.test.ts +12 -5
  74. package/src/state/ai-assistant-slice.ts +21 -13
  75. package/src/state/debug-event-log.ts +2 -2
  76. package/src/state/persistence/session-persistence-provider.ts +24 -0
  77. package/src/state/persistence/session-persistence.integration.test.ts +8 -1
  78. package/src/state/persistence/session-persister.test.ts +10 -1
  79. package/src/state/persistence/session-persister.ts +2 -2
  80. package/src/state/persistence/session-snapshot.test.ts +4 -1
  81. package/src/state/persistence/session-snapshot.ts +5 -1
  82. package/src/state/persistence/stateful-restore.e2e.test.ts +9 -1
  83. package/src/styles/settings-section.ts +40 -0
  84. package/src/utils/cost-session-history.test.ts +187 -16
  85. package/src/utils/cost-session-history.ts +142 -23
  86. package/src/utils/resolve-cost-history-config.ts +10 -3
  87. package/src/utils/sum-costs.ts +2 -9
  88. package/src/utils/sum-tokens.test.ts +1 -11
  89. package/src/utils/sum-tokens.ts +10 -26
  90. package/src/utils/sum-usage.test.ts +140 -0
  91. package/src/utils/sum-usage.ts +130 -0
@@ -1518,6 +1518,8 @@ ${att.content}` });
1518
1518
  var _a, _b, _c, _d, _e, _f, _g, _h;
1519
1519
  let inputTokens;
1520
1520
  let outputTokens;
1521
+ let cacheReadTokens;
1522
+ let cacheWriteTokens;
1521
1523
  let cost;
1522
1524
  if (response.usage) {
1523
1525
  const uncachedInput = (_a = response.usage.input_tokens) !== null && _a !== void 0 ? _a : 0;
@@ -1527,6 +1529,8 @@ ${att.content}` });
1527
1529
  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;
1528
1530
  cost = this.logTokenUsage(uncachedInput, (_f = response.usage.output_tokens) !== null && _f !== void 0 ? _f : 0, cacheRead, cacheCreation, cacheCreation1h);
1529
1531
  inputTokens = uncachedInput + cacheRead + cacheCreation;
1532
+ cacheReadTokens = cacheRead;
1533
+ cacheWriteTokens = cacheCreation;
1530
1534
  if (response.usage.output_tokens != null) {
1531
1535
  outputTokens = response.usage.output_tokens;
1532
1536
  }
@@ -1557,6 +1561,10 @@ ${att.content}` });
1557
1561
  base.inputTokens = inputTokens;
1558
1562
  if (outputTokens != null)
1559
1563
  base.outputTokens = outputTokens;
1564
+ if (cacheReadTokens != null)
1565
+ base.cacheReadTokens = cacheReadTokens;
1566
+ if (cacheWriteTokens != null)
1567
+ base.cacheWriteTokens = cacheWriteTokens;
1560
1568
  if (cost != null)
1561
1569
  base.cost = cost;
1562
1570
  if (response.stop_reason === "max_tokens") {
@@ -2083,28 +2091,45 @@ ${att.content}`
2083
2091
  }
2084
2092
  return contents;
2085
2093
  }
2094
+ /**
2095
+ * Map Gemini's `usageMetadata` onto the provider-agnostic usage fields, pricing
2096
+ * the call as a side effect (`logTokenUsage`). Returns an empty object when the
2097
+ * response carries no usage — every field is optional, so an absent count stays
2098
+ * `undefined` rather than being reported as a measured 0.
2099
+ *
2100
+ * Split out of `fromGeminiResponse` because it is self-contained bookkeeping
2101
+ * that reads better alone — and because folding it inline pushed that method
2102
+ * past the complexity ceiling.
2103
+ */
2104
+ usageFromGemini(usageMetadata) {
2105
+ var _a, _b, _c, _d, _e, _f;
2106
+ if (!usageMetadata)
2107
+ return {};
2108
+ const usage = usageMetadata;
2109
+ const cost = this.logTokenUsage((_a = usage.promptTokenCount) !== null && _a !== void 0 ? _a : 0, (_b = usage.candidatesTokenCount) !== null && _b !== void 0 ? _b : 0, (_c = usage.thoughtsTokenCount) !== null && _c !== void 0 ? _c : 0, (_d = usage.cachedContentTokenCount) !== null && _d !== void 0 ? _d : 0);
2110
+ return {
2111
+ inputTokens: usage.promptTokenCount,
2112
+ // Thinking tokens are generated output, billed at the candidate rate, but
2113
+ // reported in a field disjoint from `candidatesTokenCount`. Fold them into the
2114
+ // provider-agnostic `outputTokens` so it reflects the true generated total —
2115
+ // matching Anthropic, whose `output_tokens` already includes them. Left
2116
+ // `undefined` only when the provider reported neither count.
2117
+ outputTokens: usage.candidatesTokenCount != null || usage.thoughtsTokenCount != null ? ((_e = usage.candidatesTokenCount) !== null && _e !== void 0 ? _e : 0) + ((_f = usage.thoughtsTokenCount) !== null && _f !== void 0 ? _f : 0) : void 0,
2118
+ thoughtsTokens: usage.thoughtsTokenCount,
2119
+ // Gemini reports cache HITS only — implicit caching bills no separate write, so
2120
+ // `cacheWriteTokens` is left unset rather than 0 (there is no write bucket to
2121
+ // measure, which is not the same as measuring 0). Already counted inside
2122
+ // `promptTokenCount`, so this breaks that total down rather than adding to it.
2123
+ cacheReadTokens: usage.cachedContentTokenCount,
2124
+ cost
2125
+ };
2126
+ }
2086
2127
  fromGeminiResponse(response, offeredToolNames = /* @__PURE__ */ new Set()) {
2087
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
2088
- let inputTokens;
2089
- let outputTokens;
2090
- let thoughtsTokens;
2091
- let cost;
2092
- if (response.usageMetadata) {
2093
- const usage = response.usageMetadata;
2094
- cost = this.logTokenUsage((_a = usage.promptTokenCount) !== null && _a !== void 0 ? _a : 0, (_b = usage.candidatesTokenCount) !== null && _b !== void 0 ? _b : 0, (_c = usage.thoughtsTokenCount) !== null && _c !== void 0 ? _c : 0, (_d = usage.cachedContentTokenCount) !== null && _d !== void 0 ? _d : 0);
2095
- if (usage.promptTokenCount != null) {
2096
- inputTokens = usage.promptTokenCount;
2097
- }
2098
- if (usage.thoughtsTokenCount != null) {
2099
- thoughtsTokens = usage.thoughtsTokenCount;
2100
- }
2101
- if (usage.candidatesTokenCount != null || usage.thoughtsTokenCount != null) {
2102
- outputTokens = ((_e = usage.candidatesTokenCount) !== null && _e !== void 0 ? _e : 0) + ((_f = usage.thoughtsTokenCount) !== null && _f !== void 0 ? _f : 0);
2103
- }
2104
- }
2128
+ var _a, _b, _c, _d;
2129
+ const { inputTokens, outputTokens, thoughtsTokens, cacheReadTokens, cost } = this.usageFromGemini(response.usageMetadata);
2105
2130
  const candidates = response === null || response === void 0 ? void 0 : response.candidates;
2106
2131
  const firstCandidate = candidates === null || candidates === void 0 ? void 0 : candidates[0];
2107
- const parts = (_h = (_g = firstCandidate === null || firstCandidate === void 0 ? void 0 : firstCandidate.content) === null || _g === void 0 ? void 0 : _g.parts) !== null && _h !== void 0 ? _h : [];
2132
+ const parts = (_b = (_a = firstCandidate === null || firstCandidate === void 0 ? void 0 : firstCandidate.content) === null || _a === void 0 ? void 0 : _a.parts) !== null && _b !== void 0 ? _b : [];
2108
2133
  const toolCalls = [];
2109
2134
  const thoughtParts = [];
2110
2135
  const textParts = [];
@@ -2117,7 +2142,7 @@ ${att.content}`
2117
2142
  toolCalls.push({
2118
2143
  id: crypto.randomUUID(),
2119
2144
  name: part.functionCall.name,
2120
- args: (_j = part.functionCall.args) !== null && _j !== void 0 ? _j : {},
2145
+ args: (_c = part.functionCall.args) !== null && _c !== void 0 ? _c : {},
2121
2146
  providerMetadata: { [GEMINI_PROVIDER_KEY]: state }
2122
2147
  });
2123
2148
  } else if (part.thought && part.text) {
@@ -2151,9 +2176,11 @@ ${att.content}`
2151
2176
  base.inputTokens = inputTokens;
2152
2177
  if (outputTokens != null)
2153
2178
  base.outputTokens = outputTokens;
2179
+ if (cacheReadTokens != null)
2180
+ base.cacheReadTokens = cacheReadTokens;
2154
2181
  if (cost != null)
2155
2182
  base.cost = cost;
2156
- const blockReason = (_k = response.promptFeedback) === null || _k === void 0 ? void 0 : _k.blockReason;
2183
+ const blockReason = (_d = response.promptFeedback) === null || _d === void 0 ? void 0 : _d.blockReason;
2157
2184
  if (finishReason != null || thoughtsTokens != null || blockReason != null) {
2158
2185
  base.responseMeta = {
2159
2186
  finishReason,
@@ -2950,6 +2977,46 @@ The above summarizes earlier parts of this conversation that were compacted. Con
2950
2977
  });
2951
2978
  }
2952
2979
 
2980
+ // src/utils/sum-usage.ts
2981
+ function emptyUsage() {
2982
+ return {
2983
+ costUsd: 0,
2984
+ uncachedInputTokens: 0,
2985
+ cacheReadTokens: 0,
2986
+ cacheWriteTokens: 0,
2987
+ outputTokens: 0
2988
+ };
2989
+ }
2990
+ function sumUsage(messages) {
2991
+ const total = emptyUsage();
2992
+ accumulate(messages, total);
2993
+ return total;
2994
+ }
2995
+ function addInto(into, from) {
2996
+ into.costUsd += from.costUsd;
2997
+ into.uncachedInputTokens += from.uncachedInputTokens;
2998
+ into.cacheReadTokens += from.cacheReadTokens;
2999
+ into.cacheWriteTokens += from.cacheWriteTokens;
3000
+ into.outputTokens += from.outputTokens;
3001
+ }
3002
+ function accumulate(messages, into) {
3003
+ for (const m of messages) {
3004
+ if (m.cost != null) into.costUsd += m.cost;
3005
+ if (m.externalCostUsd != null) into.costUsd += m.externalCostUsd;
3006
+ const cacheRead = m.cacheReadTokens ?? 0;
3007
+ const cacheWrite = m.cacheWriteTokens ?? 0;
3008
+ into.cacheReadTokens += cacheRead;
3009
+ into.cacheWriteTokens += cacheWrite;
3010
+ into.uncachedInputTokens += Math.max(0, (m.inputTokens ?? 0) - cacheRead - cacheWrite);
3011
+ into.outputTokens += m.outputTokens ?? 0;
3012
+ const rolled = m.compaction?.rolledUpUsage;
3013
+ if (rolled) addInto(into, rolled);
3014
+ for (const tc of m.toolCalls ?? []) {
3015
+ if (tc.subAgentTrace) accumulate(tc.subAgentTrace, into);
3016
+ }
3017
+ }
3018
+ }
3019
+
2953
3020
  // src/utils/tool-fold.ts
2954
3021
  var TOOL_FOLD_SYMBOL = Symbol("toolFold");
2955
3022
 
@@ -3697,7 +3764,12 @@ Output format (strict):
3697
3764
  coveredThroughTimestamp: toCompact[toCompact.length - 1]?.timestamp,
3698
3765
  tokensBefore,
3699
3766
  model: status?.model,
3700
- createdAt
3767
+ createdAt,
3768
+ // Bank what the replaced turns spent. `toCompact` is dropped from history
3769
+ // below, taking its per-message cost/token fields with it — so a host total
3770
+ // re-derived from the transcript would otherwise fall by exactly this much
3771
+ // on every compaction. Summarising a turn does not refund what it cost.
3772
+ rolledUpUsage: sumUsage(toCompact)
3701
3773
  }
3702
3774
  };
3703
3775
  this.loadHistory([summaryMessage, ...tail]);