@quilltap/plugin-utils 2.6.2 → 2.7.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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to @quilltap/plugin-utils will be documented in this file.
4
4
 
5
+ ## [2.7.0] - 2026-10-13
6
+
7
+ ### Fixed
8
+
9
+ - `OpenAICompatibleProvider` now reports `usage.promptTokens` / `usage.totalTokens` with prompt-cache hits excluded, matching every other Quilltap provider. Endpoints fold cached input into `prompt_tokens` and report it as `prompt_tokens_details.cached_tokens`; that count is now subtracted (floored at 0) and surfaced as `cacheUsage` (`cacheReadInputTokens`, `cachedTokens`). The final stream chunk also carries the endpoint's own `usage` block as `rawProviderUsage`. Endpoints that report no cached tokens are unchanged. Previously, cache hits on any plugin built on the base class counted against Quilltap's autonomous-room token budgets.
10
+
11
+ ### Added
12
+
13
+ - `protected normalizeUsage(usage)` — the one place both `sendMessage` and `streamMessage` map a Chat Completions `usage` block. Subclasses that keep the base send/stream loops can override it for an endpoint that reports cache hits in a different field.
14
+
5
15
  ## [2.6.0] - 2026-08-27
6
16
 
7
17
  ### Removed
package/dist/index.d.mts CHANGED
@@ -124,6 +124,6 @@ declare function getQuilltapUserAgent(): string;
124
124
  * Version of the plugin-utils package.
125
125
  * Can be used at runtime to check compatibility.
126
126
  */
127
- declare const PLUGIN_UTILS_VERSION = "2.6.2";
127
+ declare const PLUGIN_UTILS_VERSION = "2.7.0";
128
128
 
129
129
  export { BUILTIN_TOOL_NAMES, PLUGIN_UTILS_VERSION, __clearQuilltapVersion, __injectQuilltapVersion, getBuiltinToolNames, getQuilltapUserAgent, getQuilltapVersion };
package/dist/index.d.ts CHANGED
@@ -124,6 +124,6 @@ declare function getQuilltapUserAgent(): string;
124
124
  * Version of the plugin-utils package.
125
125
  * Can be used at runtime to check compatibility.
126
126
  */
127
- declare const PLUGIN_UTILS_VERSION = "2.6.2";
127
+ declare const PLUGIN_UTILS_VERSION = "2.7.0";
128
128
 
129
129
  export { BUILTIN_TOOL_NAMES, PLUGIN_UTILS_VERSION, __clearQuilltapVersion, __injectQuilltapVersion, getBuiltinToolNames, getQuilltapUserAgent, getQuilltapVersion };
package/dist/index.js CHANGED
@@ -701,6 +701,34 @@ var OpenAICompatibleProvider = class {
701
701
  this.applyProfileParams(body, params);
702
702
  return body;
703
703
  }
704
+ /**
705
+ * Normalizes a Chat Completions `usage` block into Quilltap's shape.
706
+ *
707
+ * OpenAI-compatible endpoints fold prompt-cache hits into `prompt_tokens`
708
+ * (reported separately as `prompt_tokens_details.cached_tokens`). Quilltap's
709
+ * convention is that `promptTokens` / `totalTokens` EXCLUDE cache reads, so
710
+ * cached input never counts against token budgets; `cacheUsage` still
711
+ * carries the cache reads for display. Endpoints that report no
712
+ * `cached_tokens` are unaffected.
713
+ */
714
+ normalizeUsage(usage) {
715
+ const cachedTokens = usage?.prompt_tokens_details?.cached_tokens ?? 0;
716
+ if (cachedTokens > 0) {
717
+ this.logger.debug(`${this.providerName} usage: excluding prompt-cache hits from prompt/total`, {
718
+ context: `${this.providerName}Provider.normalizeUsage`,
719
+ promptTokens: usage?.prompt_tokens ?? 0,
720
+ cachedTokens
721
+ });
722
+ }
723
+ return {
724
+ usage: {
725
+ promptTokens: Math.max(0, (usage?.prompt_tokens ?? 0) - cachedTokens),
726
+ completionTokens: usage?.completion_tokens ?? 0,
727
+ totalTokens: Math.max(0, (usage?.total_tokens ?? 0) - cachedTokens)
728
+ },
729
+ ...cachedTokens > 0 ? { cacheUsage: { cacheReadInputTokens: cachedTokens, cachedTokens } } : {}
730
+ };
731
+ }
704
732
  /**
705
733
  * Sends a message and returns the complete response.
706
734
  *
@@ -723,11 +751,7 @@ var OpenAICompatibleProvider = class {
723
751
  return {
724
752
  content: choice.message.content ?? "",
725
753
  finishReason: choice.finish_reason,
726
- usage: {
727
- promptTokens: response.usage?.prompt_tokens ?? 0,
728
- completionTokens: response.usage?.completion_tokens ?? 0,
729
- totalTokens: response.usage?.total_tokens ?? 0
730
- },
754
+ ...this.normalizeUsage(response.usage),
731
755
  raw: response,
732
756
  attachmentResults,
733
757
  ...toolCalls.length > 0 ? { toolCalls } : {}
@@ -768,11 +792,7 @@ var OpenAICompatibleProvider = class {
768
792
  const content = choice?.delta?.content;
769
793
  const hasUsage = chunk.usage;
770
794
  if (hasUsage) {
771
- accumulatedUsage = {
772
- prompt_tokens: chunk.usage?.prompt_tokens,
773
- completion_tokens: chunk.usage?.completion_tokens,
774
- total_tokens: chunk.usage?.total_tokens
775
- };
795
+ accumulatedUsage = chunk.usage ?? null;
776
796
  }
777
797
  if (choice?.delta?.tool_calls) {
778
798
  for (const tcDelta of choice.delta.tool_calls) {
@@ -800,11 +820,10 @@ var OpenAICompatibleProvider = class {
800
820
  yield {
801
821
  content: "",
802
822
  done: true,
803
- usage: accumulatedUsage ? {
804
- promptTokens: accumulatedUsage.prompt_tokens ?? 0,
805
- completionTokens: accumulatedUsage.completion_tokens ?? 0,
806
- totalTokens: accumulatedUsage.total_tokens ?? 0
807
- } : void 0,
823
+ ...accumulatedUsage ? {
824
+ ...this.normalizeUsage(accumulatedUsage),
825
+ rawProviderUsage: accumulatedUsage
826
+ } : {},
808
827
  attachmentResults,
809
828
  // Only synthesized when the stream actually carried tool calls: the
810
829
  // host's tool detection reads `rawResponse`, and an empty one on every
@@ -1064,7 +1083,7 @@ function rewriteLocalhostUrl(url) {
1064
1083
  }
1065
1084
 
1066
1085
  // src/version.generated.ts
1067
- var PLUGIN_UTILS_VERSION = "2.6.2";
1086
+ var PLUGIN_UTILS_VERSION = "2.7.0";
1068
1087
  // Annotate the CommonJS export names for ESM import in node:
1069
1088
  0 && (module.exports = {
1070
1089
  BUILTIN_TOOL_NAMES,