@chenlongapps/opencode-token-usage 0.3.3 → 0.4.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/pricing.js CHANGED
@@ -2,7 +2,7 @@ export const OFFICIAL_PRICE_SNAPSHOT = {
2
2
  verified: "2026-09-23",
3
3
  newModelCutoff: "2026-03-22",
4
4
  entries: [
5
- // OpenAI standard processing. Tier sizes are exclusive thresholds, so
5
+ // OpenAI API rates. Tier sizes are exclusive thresholds, so
6
6
  // 272,000 implements the official ">272K input tokens" boundary.
7
7
  {
8
8
  id: "gpt-5.5", released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
@@ -11,6 +11,14 @@ export const OFFICIAL_PRICE_SNAPSHOT = {
11
11
  { tier: { type: "context", size: 272_000 }, input: 10, output: 45, cache: { read: 1 } },
12
12
  ],
13
13
  },
14
+ {
15
+ id: "gpt-5.5-fast", providers: ["openai"], released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
16
+ prices: [
17
+ { input: 12.5, output: 75, cache: { read: 1.25 } },
18
+ // OpenAI publishes no Fast rate for GPT-5.5 above 272K input tokens.
19
+ { tier: { type: "context", size: 272_000 } },
20
+ ],
21
+ },
14
22
  {
15
23
  id: "gpt-5.5-pro", released: "2026-04-23", source: "https://developers.openai.com/api/docs/pricing",
16
24
  prices: [
@@ -60,6 +68,50 @@ export const OFFICIAL_PRICE_SNAPSHOT = {
60
68
  { tier: { type: "context", size: 272_000 }, input: 0.2, output: 0.75, cache: { read: 0.02, write: 0.25 } },
61
69
  ],
62
70
  },
71
+ {
72
+ // OpenAI Fast processing is a separate exact ID and restricted to the
73
+ // first-party provider so ordinary or gateway model IDs keep standard rates.
74
+ id: "gpt-6-luna-fast", providers: ["openai"], released: "2026-09-22", source: "https://developers.openai.com/api/docs/pricing",
75
+ prices: [
76
+ { input: 0.2, output: 1, cache: { read: 0.02, write: 0.25 } },
77
+ { tier: { type: "context", size: 272_000 }, input: 0.4, output: 1.5, cache: { read: 0.04, write: 0.5 } },
78
+ ],
79
+ },
80
+ {
81
+ id: "gpt-5.6-sol-fast", providers: ["openai"], released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
82
+ prices: [
83
+ { input: 8, output: 40, cache: { read: 0.8, write: 10 } },
84
+ { tier: { type: "context", size: 272_000 }, input: 16, output: 60, cache: { read: 1.6, write: 20 } },
85
+ ],
86
+ },
87
+ {
88
+ id: "gpt-5.6-terra-fast", providers: ["openai"], released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
89
+ prices: [
90
+ { input: 4, output: 24, cache: { read: 0.4, write: 5 } },
91
+ { tier: { type: "context", size: 272_000 }, input: 8, output: 36, cache: { read: 0.8, write: 10 } },
92
+ ],
93
+ },
94
+ {
95
+ id: "gpt-5.6-luna-fast", providers: ["openai"], released: "2026-07-09", source: "https://developers.openai.com/api/docs/pricing",
96
+ prices: [
97
+ { input: 0.4, output: 2.4, cache: { read: 0.04, write: 0.5 } },
98
+ { tier: { type: "context", size: 272_000 }, input: 0.8, output: 3.6, cache: { read: 0.08, write: 1 } },
99
+ ],
100
+ },
101
+ {
102
+ id: "gpt-6-astra-fast", providers: ["openai"], released: "2026-09-04", source: "https://developers.openai.com/api/docs/pricing",
103
+ prices: [
104
+ { input: 20, output: 100, cache: { read: 2, write: 25 } },
105
+ { tier: { type: "context", size: 272_000 }, input: 40, output: 150, cache: { read: 4, write: 50 } },
106
+ ],
107
+ },
108
+ {
109
+ id: "gpt-6-sol-fast", providers: ["openai"], released: "2026-09-22", source: "https://developers.openai.com/api/docs/pricing",
110
+ prices: [
111
+ { input: 4, output: 20, cache: { read: 0.4, write: 5 } },
112
+ { tier: { type: "context", size: 272_000 }, input: 8, output: 30, cache: { read: 0.8, write: 10 } },
113
+ ],
114
+ },
63
115
  // The official ChatGPT SKU `chat-latest`. OpenRouter serves it under the
64
116
  // slug `openai/gpt-chat-latest`, which is registered as an exact alias.
65
117
  {
@@ -89,6 +141,20 @@ export const OFFICIAL_PRICE_SNAPSHOT = {
89
141
  id: "claude-opus-5", released: "2026-07-24", source: "https://platform.claude.com/docs/en/about-claude/pricing",
90
142
  prices: [{ input: 5, output: 25, cache: { read: 0.5, write: 6.25 } }],
91
143
  },
144
+ {
145
+ // Fast mode is first-party Claude API only. Cache multipliers apply to
146
+ // the Fast input price; aggregate cache writes use the 5-minute rate.
147
+ id: "claude-opus-5-fast", providers: ["anthropic"], released: "2026-07-24", source: "https://platform.claude.com/docs/en/about-claude/pricing",
148
+ prices: [{ input: 10, output: 50, cache: { read: 1, write: 12.5 } }],
149
+ },
150
+ {
151
+ id: "claude-opus-4-8-fast", providers: ["anthropic"], released: "2026-05-28", source: "https://platform.claude.com/docs/en/about-claude/pricing",
152
+ prices: [{ input: 10, output: 50, cache: { read: 1, write: 12.5 } }],
153
+ },
154
+ {
155
+ id: "claude-opus-5-5-fast", providers: ["anthropic"], released: "2026-09-22", source: "https://platform.claude.com/docs/en/about-claude/pricing",
156
+ prices: [{ input: 8, output: 40, cache: { read: 0.4, write: 10 } }],
157
+ },
92
158
  {
93
159
  id: "claude-fable-5-1", aliases: ["claude-fable-5.1"], released: "2026-09-01",
94
160
  source: "https://platform.claude.com/docs/en/about-claude/pricing",
@@ -502,8 +568,14 @@ export function officialPrice(model) {
502
568
  const dot = id.lastIndexOf(".");
503
569
  if (dot >= 0)
504
570
  candidates.push(id.slice(dot + 1));
505
- for (const candidate of candidates) {
571
+ const available = (candidate) => {
506
572
  const entry = index.get(candidate);
573
+ return entry && (!entry.providers || entry.providers.some(provider => provider.toLowerCase() === model.providerID.toLowerCase()))
574
+ ? entry
575
+ : undefined;
576
+ };
577
+ for (const candidate of candidates) {
578
+ const entry = available(candidate);
507
579
  if (entry)
508
580
  return entry;
509
581
  }
@@ -511,7 +583,7 @@ export function officialPrice(model) {
511
583
  for (const suffix of ["-free", ":free"]) {
512
584
  if (!candidate.endsWith(suffix))
513
585
  continue;
514
- const entry = index.get(candidate.slice(0, -suffix.length));
586
+ const entry = available(candidate.slice(0, -suffix.length));
515
587
  if (entry)
516
588
  return entry;
517
589
  }
package/dist/source.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { OpenCodeClient, SessionInfo } from "@opencode/client";
2
+ import type { ContextSources } from "./context-sources.js";
2
3
  import type { PriceCatalog, UsageMessage } from "./usage.js";
3
- export type Session = Pick<SessionInfo, "id" | "parentID" | "fork" | "model" | "location">;
4
+ export type Session = Pick<SessionInfo, "id" | "parentID" | "fork" | "model" | "location" | "title">;
4
5
  export interface Page<T> {
5
6
  data: T[];
6
7
  cursor: {
@@ -19,6 +20,7 @@ export interface UsageSource {
19
20
  children(id: string, cursor: string | undefined, signal: AbortSignal): Promise<Page<Session>>;
20
21
  messages(id: string, cursor: string | undefined, signal: AbortSignal): Promise<Page<UsageMessage>>;
21
22
  model(session: Session, signal: AbortSignal): Promise<ActiveModel>;
23
+ composition?(session: Session, signal: AbortSignal): Promise<ContextSources | undefined>;
22
24
  }
23
25
  export declare function createSource(client: OpenCodeClient): UsageSource;
24
26
  export declare function pages<T>(read: (cursor?: string) => Promise<Page<T>>, signal: AbortSignal): Promise<T[]>;
package/dist/source.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { ContextSourceRpc } from "./context-rpc.js";
2
+ import { parseContextSources } from "./context-sources.js";
1
3
  import { modelKey } from "./usage.js";
2
4
  export function createSource(client) {
3
5
  return {
@@ -21,6 +23,12 @@ export function createSource(client) {
21
23
  context: model?.limit?.context,
22
24
  };
23
25
  },
26
+ async composition(session, signal) {
27
+ const response = await client.rpc(ContextSourceRpc).latest({ sessionID: session.id }, { location: session.location, signal });
28
+ if (!response || typeof response !== "object" || !("estimate" in response))
29
+ return undefined;
30
+ return parseContextSources(response.estimate);
31
+ },
24
32
  };
25
33
  }
26
34
  export async function pages(read, signal) {