@apicity/cost 0.1.0-alpha.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/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/src/compute.d.ts +3 -0
  4. package/dist/src/compute.d.ts.map +1 -0
  5. package/dist/src/compute.js +144 -0
  6. package/dist/src/compute.js.map +1 -0
  7. package/dist/src/cost.d.ts +3 -0
  8. package/dist/src/cost.d.ts.map +1 -0
  9. package/dist/src/cost.js +7 -0
  10. package/dist/src/cost.js.map +1 -0
  11. package/dist/src/extract/anthropic.d.ts +3 -0
  12. package/dist/src/extract/anthropic.d.ts.map +1 -0
  13. package/dist/src/extract/anthropic.js +26 -0
  14. package/dist/src/extract/anthropic.js.map +1 -0
  15. package/dist/src/extract/chat.d.ts +3 -0
  16. package/dist/src/extract/chat.d.ts.map +1 -0
  17. package/dist/src/extract/chat.js +29 -0
  18. package/dist/src/extract/chat.js.map +1 -0
  19. package/dist/src/extract/messages.d.ts +6 -0
  20. package/dist/src/extract/messages.d.ts.map +1 -0
  21. package/dist/src/extract/messages.js +46 -0
  22. package/dist/src/extract/messages.js.map +1 -0
  23. package/dist/src/extract/openai.d.ts +3 -0
  24. package/dist/src/extract/openai.d.ts.map +1 -0
  25. package/dist/src/extract/openai.js +31 -0
  26. package/dist/src/extract/openai.js.map +1 -0
  27. package/dist/src/extract/types.d.ts +13 -0
  28. package/dist/src/extract/types.d.ts.map +1 -0
  29. package/dist/src/extract/types.js +2 -0
  30. package/dist/src/extract/types.js.map +1 -0
  31. package/dist/src/extract/xai.d.ts +3 -0
  32. package/dist/src/extract/xai.d.ts.map +1 -0
  33. package/dist/src/extract/xai.js +30 -0
  34. package/dist/src/extract/xai.js.map +1 -0
  35. package/dist/src/index.d.ts +9 -0
  36. package/dist/src/index.d.ts.map +1 -0
  37. package/dist/src/index.js +5 -0
  38. package/dist/src/index.js.map +1 -0
  39. package/dist/src/pricing/alibaba.d.ts +3 -0
  40. package/dist/src/pricing/alibaba.d.ts.map +1 -0
  41. package/dist/src/pricing/alibaba.js +16 -0
  42. package/dist/src/pricing/alibaba.js.map +1 -0
  43. package/dist/src/pricing/anthropic.d.ts +3 -0
  44. package/dist/src/pricing/anthropic.d.ts.map +1 -0
  45. package/dist/src/pricing/anthropic.js +56 -0
  46. package/dist/src/pricing/anthropic.js.map +1 -0
  47. package/dist/src/pricing/elevenlabs.d.ts +3 -0
  48. package/dist/src/pricing/elevenlabs.d.ts.map +1 -0
  49. package/dist/src/pricing/elevenlabs.js +24 -0
  50. package/dist/src/pricing/elevenlabs.js.map +1 -0
  51. package/dist/src/pricing/fireworks.d.ts +3 -0
  52. package/dist/src/pricing/fireworks.d.ts.map +1 -0
  53. package/dist/src/pricing/fireworks.js +22 -0
  54. package/dist/src/pricing/fireworks.js.map +1 -0
  55. package/dist/src/pricing/helpers.d.ts +5 -0
  56. package/dist/src/pricing/helpers.d.ts.map +1 -0
  57. package/dist/src/pricing/helpers.js +33 -0
  58. package/dist/src/pricing/helpers.js.map +1 -0
  59. package/dist/src/pricing/index.d.ts +14 -0
  60. package/dist/src/pricing/index.d.ts.map +1 -0
  61. package/dist/src/pricing/index.js +30 -0
  62. package/dist/src/pricing/index.js.map +1 -0
  63. package/dist/src/pricing/kie.d.ts +3 -0
  64. package/dist/src/pricing/kie.d.ts.map +1 -0
  65. package/dist/src/pricing/kie.js +271 -0
  66. package/dist/src/pricing/kie.js.map +1 -0
  67. package/dist/src/pricing/kimicoding.d.ts +3 -0
  68. package/dist/src/pricing/kimicoding.d.ts.map +1 -0
  69. package/dist/src/pricing/kimicoding.js +15 -0
  70. package/dist/src/pricing/kimicoding.js.map +1 -0
  71. package/dist/src/pricing/openai.d.ts +3 -0
  72. package/dist/src/pricing/openai.d.ts.map +1 -0
  73. package/dist/src/pricing/openai.js +24 -0
  74. package/dist/src/pricing/openai.js.map +1 -0
  75. package/dist/src/pricing/types.d.ts +28 -0
  76. package/dist/src/pricing/types.d.ts.map +1 -0
  77. package/dist/src/pricing/types.js +9 -0
  78. package/dist/src/pricing/types.js.map +1 -0
  79. package/dist/src/pricing/xai.d.ts +3 -0
  80. package/dist/src/pricing/xai.d.ts.map +1 -0
  81. package/dist/src/pricing/xai.js +12 -0
  82. package/dist/src/pricing/xai.js.map +1 -0
  83. package/dist/src/slugs.d.ts +231 -0
  84. package/dist/src/slugs.d.ts.map +1 -0
  85. package/dist/src/slugs.js +278 -0
  86. package/dist/src/slugs.js.map +1 -0
  87. package/dist/src/types.d.ts +30 -0
  88. package/dist/src/types.d.ts.map +1 -0
  89. package/dist/src/types.js +2 -0
  90. package/dist/src/types.js.map +1 -0
  91. package/package.json +47 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Justin Tanner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @apicity/cost
2
+
3
+ Cross-provider cost & token estimation for the [apicity](https://github.com/justintanner/apicity) monorepo. Returns a USD figure for a planned API call across **every** apicity provider — using the upstream estimate endpoint where one exists, and a bundled hardcoded rate table otherwise.
4
+
5
+ This is the only `@apicity/*` package that depends on other workspace packages — it's a deliberate cross-provider helper, not a wrapper for any single upstream API.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @apicity/cost
11
+ # or
12
+ pnpm add @apicity/cost
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ `c.estimate(req)` accepts the **exact JSON body you would POST to upstream**. The package lightly parses the payload to extract the fields that affect price (model, resolution, duration, message contents, etc.) — so the same object you build for the real generation call doubles as the input to the cost estimate.
18
+
19
+ ```ts
20
+ import { cost } from "@apicity/cost";
21
+
22
+ const c = cost({
23
+ openai: { apiKey: process.env.OPENAI_API_KEY! },
24
+ anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! },
25
+ fal: { apiKey: process.env.FAL_API_KEY! },
26
+ // fireworks / alibaba / elevenlabs / kie / free need NO opts — pure local math
27
+ });
28
+
29
+ // openai chat — same body you'd POST to /v1/chat/completions
30
+ const a = await c.estimate({
31
+ provider: "openai",
32
+ payload: {
33
+ model: "gpt-5",
34
+ messages: [{ role: "user", content: "Estimate this prompt's cost." }],
35
+ max_tokens: 1000,
36
+ },
37
+ });
38
+ // → { usd: 0.01..., source: "tokens-api+table", breakdown: { inputTokens: 7, outputTokens: 1000, ... } }
39
+
40
+ // Skip the network call — use chars/4 heuristic
41
+ const a2 = await c.estimate({
42
+ provider: "openai",
43
+ payload: { model: "gpt-5", messages: [...], max_tokens: 1000 },
44
+ useHeuristic: true,
45
+ });
46
+
47
+ // fal — payload is whatever the chosen endpoint expects; defers to upstream USD endpoint
48
+ const f = await c.estimate({
49
+ provider: "fal",
50
+ endpoint_id: "fal-ai/flux/dev",
51
+ payload: { unit_quantity: 100 },
52
+ });
53
+ // → { usd: ..., source: "upstream-usd", rateAsOf: null }
54
+
55
+ // kie — the same body you'd POST to /api/v1/jobs/createTask
56
+ const k = await c.estimate({
57
+ provider: "kie",
58
+ payload: {
59
+ model: "bytedance/seedance-2",
60
+ input: {
61
+ prompt: "...",
62
+ first_frame_url: "https://...",
63
+ resolution: "720p",
64
+ duration: 8,
65
+ web_search: false,
66
+ },
67
+ },
68
+ });
69
+ // extractor reads model + input.resolution + first_frame_url presence (i2v)
70
+ // + input.duration → seedance-2-720p-i2v rate × 8 seconds
71
+
72
+ // elevenlabs TTS — payload is the /v1/text-to-speech body
73
+ const e = await c.estimate({
74
+ provider: "elevenlabs",
75
+ payload: { model_id: "eleven_flash_v2_5", text: "Hello world" },
76
+ });
77
+
78
+ // free → always $0
79
+ const z = await c.estimate({ provider: "free-media-upload" });
80
+ ```
81
+
82
+ ## Return shape
83
+
84
+ ```ts
85
+ interface CostEstimate {
86
+ usd: number;
87
+ currency: "USD";
88
+ source:
89
+ | "upstream-usd" // fal — exact USD from upstream
90
+ | "tokens-api+table" // openai/anthropic/xai — exact tokens × bundled rate
91
+ | "tokens-heuristic+table" // useHeuristic:true, plus fireworks/alibaba/kimicoding (always heuristic)
92
+ | "per-unit-table" // elevenlabs/kie — payload-derived units × bundled rate
93
+ | "free";
94
+ breakdown: {
95
+ inputTokens?: number;
96
+ outputTokens?: number;
97
+ units?: number;
98
+ unit?: "tokens" | "characters" | "seconds" | "images" | "songs";
99
+ inputUsdPerMillion?: number;
100
+ outputUsdPerMillion?: number;
101
+ perUnitUsd?: number;
102
+ };
103
+ rateAsOf: string | null; // YYYY-MM-DD; null when source=upstream-usd
104
+ warnings: string[]; // non-empty when fallback fired (unknown model, missing max_tokens, missing duration, etc.)
105
+ }
106
+ ```
107
+
108
+ `source` is the load-bearing field: callers who want guarantees check `source === "upstream-usd"`. Callers who tolerate ±20% can accept `tokens-api+table` and `per-unit-table`. Heuristic mode (`tokens-heuristic+table`) is rougher — chars/4 ≈ tokens.
109
+
110
+ ## How payloads are parsed
111
+
112
+ Each provider has a small extractor in `src/extract/` that walks the payload looking for the fields the rate table discriminates on. Unrecognized payloads return `usd: 0` plus a warning rather than throwing — so a missing `input.resolution` on a kie seedance payload, or a model not in the bundled table, produces a diagnosable `CostEstimate` rather than an exception.
113
+
114
+ For text providers (openai / anthropic / xai / kimicoding / fireworks / alibaba), the extractor flattens the chat `messages` array (or `input` / `prompt` / `text`) into a single string for token counting; non-text content parts (images, audio, tool calls) are dropped.
115
+
116
+ For kie, the rate table keys are not 1:1 with the payload's `model` field — the extractor rebuilds them from the payload's `input.resolution`, `input.first_frame_url` (i2v vs t2v), and the marketplace model slug. See `src/extract/kie.ts` for the full mapping. Image models (nano-banana-2, gpt-image-2, qwen2, seedream/5-lite, wan/2-7-image) price per image; resolution-tiered families require `input.resolution`.
117
+
118
+ ## Bundled pricing
119
+
120
+ Rates are frozen at `PRICING_AS_OF` (currently `2026-04-30`) and shipped in `src/pricing.ts`. They cover the most common model on each provider; calling `estimate()` with an unknown model returns `usd: 0` plus a warning, never throws.
121
+
122
+ To inspect what's bundled:
123
+
124
+ ```ts
125
+ import { TOKEN_RATES, PER_UNIT_RATES, PRICING_AS_OF } from "@apicity/cost";
126
+ ```
127
+
128
+ Maintenance is manual: re-fetch each upstream's pricing page, edit `pricing.ts`, bump `PRICING_AS_OF`.
129
+
130
+ ## Coverage
131
+
132
+ | Provider | source | Notes |
133
+ | ------------ | ------------------------ | --------------------------------------------------------------------- |
134
+ | `openai` | `tokens-api+table` | wraps `POST /v1/responses/input_tokens` |
135
+ | `anthropic` | `tokens-api+table` | wraps `POST /v1/messages/count_tokens` |
136
+ | `xai` | `tokens-api+table` | wraps `POST /v1/tokenize-text` |
137
+ | `kimicoding` | `tokens-heuristic+table` | upstream `/coding/v1/tokens/count` returns 404 — local heuristic only |
138
+ | `fireworks` | `tokens-heuristic+table` | no upstream estimate endpoint |
139
+ | `alibaba` | `tokens-heuristic+table` | no upstream estimate endpoint |
140
+ | `fal` | `upstream-usd` | wraps `POST /v1/models/pricing/estimate` |
141
+ | `elevenlabs` | `per-unit-table` | priced per character |
142
+ | `kie` | `per-unit-table` | priced per second of video / per image |
143
+ | `free` | `free` | always $0 |
144
+
145
+ ## Out of scope
146
+
147
+ - Anthropic prompt-cache pricing (rates are in the table but `estimate()` ignores them — assumes no caching)
148
+ - Batch API discount (50% off across providers)
149
+ - Tier-based fallback for fireworks (parameter-count brackets)
150
+ - Suno per-song pricing on kie (no stable published rate)
151
+ - Caller-side `pricingOverrides`
152
+
153
+ Part of the [apicity](https://github.com/justintanner/apicity) monorepo.
154
+
155
+ ## License
156
+
157
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,3 @@
1
+ import type { CostEstimate, EstimateRequest } from "./types";
2
+ export declare function computeEstimate(req: EstimateRequest): CostEstimate;
3
+ //# sourceMappingURL=compute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../src/compute.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAc,eAAe,EAAE,MAAM,SAAS,CAAC;AA4HzE,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,YAAY,CA+ClE"}
@@ -0,0 +1,144 @@
1
+ import { PRICING, PRICING_AS_OF } from "./pricing/index.js";
2
+ import { asString } from "./pricing/helpers.js";
3
+ import { extractAnthropic } from "./extract/anthropic.js";
4
+ import { extractChat } from "./extract/chat.js";
5
+ import { extractOpenAi } from "./extract/openai.js";
6
+ import { extractXai } from "./extract/xai.js";
7
+ const heuristicTokens = (text) => Math.ceil(text.length / 4);
8
+ function failed(source, warnings) {
9
+ return {
10
+ usd: 0,
11
+ currency: "USD",
12
+ source,
13
+ breakdown: {},
14
+ rateAsOf: PRICING_AS_OF,
15
+ warnings,
16
+ };
17
+ }
18
+ function applyTokenRate(provider, model, inputTokens, maxOutputTokens) {
19
+ const entry = PRICING[provider][model];
20
+ const warnings = [];
21
+ const outputTokens = maxOutputTokens ?? 0;
22
+ if (maxOutputTokens === undefined) {
23
+ warnings.push("maxOutputTokens not provided; output cost not included in estimate");
24
+ }
25
+ const source = "tokens-heuristic+table";
26
+ if (!entry || entry.kind !== "tokens") {
27
+ warnings.push(`model '${model}' not found in pricing table for provider '${provider}'`);
28
+ return {
29
+ usd: 0,
30
+ currency: "USD",
31
+ source,
32
+ breakdown: { inputTokens, outputTokens, unit: "tokens" },
33
+ rateAsOf: PRICING_AS_OF,
34
+ warnings,
35
+ };
36
+ }
37
+ const { rate } = entry;
38
+ const usd = (inputTokens * rate.input + outputTokens * rate.output) / 1_000_000;
39
+ return {
40
+ usd,
41
+ currency: "USD",
42
+ source,
43
+ breakdown: {
44
+ inputTokens,
45
+ outputTokens,
46
+ unit: "tokens",
47
+ inputUsdPerMillion: rate.input,
48
+ outputUsdPerMillion: rate.output,
49
+ },
50
+ rateAsOf: entry.source.asOf ?? PRICING_AS_OF,
51
+ warnings,
52
+ };
53
+ }
54
+ // Generic dispatcher for per-unit providers (kie, elevenlabs). Reads the
55
+ // pricing key from the explicit `endpoint` discriminator first (used by
56
+ // providers like Suno whose pricing is keyed by endpoint, not model
57
+ // version), then falls back to payload.model / payload.model_id. Looks up
58
+ // the entry, runs `units(payload)` and the ordered selectors, and returns
59
+ // the matching rate. All payload-shape knowledge lives in the model
60
+ // entry's closures.
61
+ function evaluatePerUnit(provider, payload, endpoint) {
62
+ const model = endpoint ?? asString(payload.model) ?? asString(payload.model_id);
63
+ if (!model) {
64
+ return failed("per-unit-table", [
65
+ `${provider}: endpoint or payload.model is required`,
66
+ ]);
67
+ }
68
+ const entry = PRICING[provider][model];
69
+ if (!entry) {
70
+ return failed("per-unit-table", [
71
+ `model '${model}' not found in pricing table for provider '${provider}'`,
72
+ ]);
73
+ }
74
+ if (entry.kind !== "perUnit") {
75
+ return failed("per-unit-table", [
76
+ `${provider} '${model}' is token-billed, not per-unit`,
77
+ ]);
78
+ }
79
+ const units = entry.units(payload);
80
+ if (units === undefined) {
81
+ return failed("per-unit-table", [
82
+ `${provider} '${model}': could not derive units from payload (check duration / text)`,
83
+ ]);
84
+ }
85
+ const variantKey = entry.select
86
+ .map((s) => s.pick(payload))
87
+ .filter((v) => Boolean(v))
88
+ .join("|");
89
+ const perUnit = entry.rates[variantKey];
90
+ if (perUnit === undefined) {
91
+ const selectorNames = entry.select.map((s) => s.name).join(", ");
92
+ return failed("per-unit-table", [
93
+ `${provider} '${model}': no rate for variant '${variantKey}' (selectors: ${selectorNames})`,
94
+ ]);
95
+ }
96
+ return {
97
+ usd: units * perUnit,
98
+ currency: "USD",
99
+ source: "per-unit-table",
100
+ breakdown: { units, unit: entry.unit, perUnitUsd: perUnit },
101
+ rateAsOf: entry.source.asOf ?? PRICING_AS_OF,
102
+ warnings: [],
103
+ };
104
+ }
105
+ export function computeEstimate(req) {
106
+ switch (req.provider) {
107
+ case "openai":
108
+ case "anthropic":
109
+ case "xai": {
110
+ const ext = req.provider === "openai"
111
+ ? extractOpenAi(req.payload)
112
+ : req.provider === "anthropic"
113
+ ? extractAnthropic(req.payload)
114
+ : extractXai(req.payload);
115
+ if (!ext.ok)
116
+ return failed("tokens-heuristic+table", ext.warnings);
117
+ const inputTokens = heuristicTokens(ext.data.text);
118
+ return applyTokenRate(req.provider, ext.data.model, inputTokens, ext.data.maxOutputTokens);
119
+ }
120
+ case "fireworks":
121
+ case "alibaba":
122
+ case "kimicoding": {
123
+ const ext = extractChat(req.provider, req.payload);
124
+ if (!ext.ok)
125
+ return failed("tokens-heuristic+table", ext.warnings);
126
+ const inputTokens = heuristicTokens(ext.data.text);
127
+ return applyTokenRate(req.provider, ext.data.model, inputTokens, ext.data.maxOutputTokens);
128
+ }
129
+ case "kie":
130
+ return evaluatePerUnit("kie", req.payload, req.endpoint);
131
+ case "elevenlabs":
132
+ return evaluatePerUnit("elevenlabs", req.payload, req.endpoint);
133
+ case "free-media-upload":
134
+ return {
135
+ usd: 0,
136
+ currency: "USD",
137
+ source: "free",
138
+ breakdown: {},
139
+ rateAsOf: PRICING_AS_OF,
140
+ warnings: [],
141
+ };
142
+ }
143
+ }
144
+ //# sourceMappingURL=compute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.js","sourceRoot":"","sources":["../../src/compute.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CostProvider } from "./types";
2
+ export declare function cost(): CostProvider;
3
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/cost.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,SAAS,CAAC;AAE7D,wBAAgB,IAAI,IAAI,YAAY,CAInC"}
@@ -0,0 +1,7 @@
1
+ import { computeEstimate } from "./compute.js";
2
+ export function cost() {
3
+ return {
4
+ estimate: (req) => computeEstimate(req),
5
+ };
6
+ }
7
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/cost.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,MAAM,UAAU,IAAI;IAClB,OAAO;QACL,QAAQ,EAAE,CAAC,GAAoB,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC;KACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ExtractResult, TextExtract } from "./types";
2
+ export declare function extractAnthropic(payload: Record<string, unknown>): ExtractResult<TextExtract>;
3
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/extract/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAK1D,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa,CAAC,WAAW,CAAC,CA0B5B"}
@@ -0,0 +1,26 @@
1
+ import { asString, flattenMessages, pickMaxOutputTokens } from "./messages.js";
2
+ // Accepts an anthropic /v1/messages payload (`{model, messages, system?}`).
3
+ // `system` may be a string or an array of content blocks.
4
+ export function extractAnthropic(payload) {
5
+ const model = asString(payload.model);
6
+ if (!model) {
7
+ return { ok: false, warnings: ["anthropic: payload.model is required"] };
8
+ }
9
+ let systemText = "";
10
+ if (typeof payload.system === "string") {
11
+ systemText = payload.system;
12
+ }
13
+ else if (Array.isArray(payload.system)) {
14
+ const blocks = payload.system.filter((b) => b !== null &&
15
+ typeof b === "object" &&
16
+ typeof b.text === "string");
17
+ systemText = blocks.map((b) => b.text).join("\n");
18
+ }
19
+ const messageText = flattenMessages(payload.messages);
20
+ const text = [systemText, messageText].filter(Boolean).join("\n");
21
+ return {
22
+ ok: true,
23
+ data: { model, text, maxOutputTokens: pickMaxOutputTokens(payload) },
24
+ };
25
+ }
26
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/extract/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5E,4EAA4E;AAC5E,0DAA0D;AAC1D,MAAM,UAAU,gBAAgB,CAC9B,OAAgC;IAEhC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,sCAAsC,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACvC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAClC,CAAC,CAAC,EAAyB,EAAE,CAC3B,CAAC,KAAK,IAAI;YACV,OAAO,CAAC,KAAK,QAAQ;YACrB,OAAQ,CAAwB,CAAC,IAAI,KAAK,QAAQ,CACrD,CAAC;QACF,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAElE,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE;KACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ExtractResult, TextExtract } from "./types";
2
+ export declare function extractChat(provider: "kimicoding" | "fireworks" | "alibaba", payload: Record<string, unknown>): ExtractResult<TextExtract>;
3
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/extract/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAO1D,wBAAgB,WAAW,CACzB,QAAQ,EAAE,YAAY,GAAG,WAAW,GAAG,SAAS,EAChD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa,CAAC,WAAW,CAAC,CAqB5B"}
@@ -0,0 +1,29 @@
1
+ import { asString, flattenMessages, pickMaxOutputTokens } from "./messages.js";
2
+ // Generic chat-completions extractor used for kimicoding / fireworks /
3
+ // alibaba — providers that share the OpenAI-compatible chat shape but have
4
+ // no upstream count-tokens endpoint, so they always run through the
5
+ // chars/4 heuristic. `provider` is only used for the missing-model warning.
6
+ export function extractChat(provider, payload) {
7
+ const model = asString(payload.model);
8
+ if (!model) {
9
+ return { ok: false, warnings: [`${provider}: payload.model is required`] };
10
+ }
11
+ let text = "";
12
+ if (Array.isArray(payload.messages)) {
13
+ text = flattenMessages(payload.messages);
14
+ }
15
+ else if (typeof payload.prompt === "string") {
16
+ text = payload.prompt;
17
+ }
18
+ else if (typeof payload.text === "string") {
19
+ text = payload.text;
20
+ }
21
+ else if (typeof payload.input === "string") {
22
+ text = payload.input;
23
+ }
24
+ return {
25
+ ok: true,
26
+ data: { model, text, maxOutputTokens: pickMaxOutputTokens(payload) },
27
+ };
28
+ }
29
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/extract/chat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5E,uEAAuE;AACvE,2EAA2E;AAC3E,oEAAoE;AACpE,4EAA4E;AAC5E,MAAM,UAAU,WAAW,CACzB,QAAgD,EAChD,OAAgC;IAEhC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,6BAA6B,CAAC,EAAE,CAAC;IAC7E,CAAC;IAED,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC9C,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IACxB,CAAC;SAAM,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5C,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;SAAM,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC7C,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE;KACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function flattenMessages(messages: unknown): string;
2
+ export declare function asString(x: unknown): string | undefined;
3
+ export declare function asNumber(x: unknown): number | undefined;
4
+ export declare function asObject(x: unknown): Record<string, unknown> | undefined;
5
+ export declare function pickMaxOutputTokens(payload: Record<string, unknown>): number | undefined;
6
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/extract/messages.ts"],"names":[],"mappings":"AAcA,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAoBzD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEvD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEvD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAIxE;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,GAAG,SAAS,CAMpB"}
@@ -0,0 +1,46 @@
1
+ // Walks a chat-style messages array and joins all text content into a single
2
+ // string for token counting. Non-text content parts (image_url, audio, tool
3
+ // calls) are skipped — image/audio token costs are out of scope, matching
4
+ // existing behavior.
5
+ export function flattenMessages(messages) {
6
+ if (!Array.isArray(messages))
7
+ return "";
8
+ const parts = [];
9
+ for (const m of messages) {
10
+ if (m === null || typeof m !== "object")
11
+ continue;
12
+ const msg = m;
13
+ const c = msg.content;
14
+ if (typeof c === "string") {
15
+ parts.push(c);
16
+ }
17
+ else if (Array.isArray(c)) {
18
+ for (const p of c) {
19
+ if (p === null || typeof p !== "object")
20
+ continue;
21
+ const part = p;
22
+ if (part.type === "text" && typeof part.text === "string") {
23
+ parts.push(part.text);
24
+ }
25
+ }
26
+ }
27
+ }
28
+ return parts.join("\n");
29
+ }
30
+ export function asString(x) {
31
+ return typeof x === "string" ? x : undefined;
32
+ }
33
+ export function asNumber(x) {
34
+ return typeof x === "number" && Number.isFinite(x) ? x : undefined;
35
+ }
36
+ export function asObject(x) {
37
+ return x !== null && typeof x === "object" && !Array.isArray(x)
38
+ ? x
39
+ : undefined;
40
+ }
41
+ export function pickMaxOutputTokens(payload) {
42
+ return (asNumber(payload.max_tokens) ??
43
+ asNumber(payload.max_output_tokens) ??
44
+ asNumber(payload.max_completion_tokens));
45
+ }
46
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/extract/messages.ts"],"names":[],"mappings":"AAUA,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,qBAAqB;AACrB,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAClD,MAAM,GAAG,GAAG,CAAY,CAAC;QACzB,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;QACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClB,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;oBAAE,SAAS;gBAClD,MAAM,IAAI,GAAG,CAAgB,CAAC;gBAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC1D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAE,CAA6B;QAChC,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAgC;IAEhC,OAAO,CACL,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC;QAC5B,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QACnC,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,CACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ExtractResult, TextExtract } from "./types";
2
+ export declare function extractOpenAi(payload: Record<string, unknown>): ExtractResult<TextExtract>;
3
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/extract/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAM1D,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa,CAAC,WAAW,CAAC,CAwB5B"}
@@ -0,0 +1,31 @@
1
+ import { asString, flattenMessages, pickMaxOutputTokens } from "./messages.js";
2
+ // Accepts either a chat completions payload (`{model, messages}`) or a
3
+ // responses payload (`{model, input}`). For responses the `input` may be a
4
+ // flat string or an array of message-like objects.
5
+ export function extractOpenAi(payload) {
6
+ const model = asString(payload.model);
7
+ if (!model) {
8
+ return { ok: false, warnings: ["openai: payload.model is required"] };
9
+ }
10
+ let text = "";
11
+ if (typeof payload.input === "string") {
12
+ text = payload.input;
13
+ }
14
+ else if (Array.isArray(payload.input)) {
15
+ text = flattenMessages(payload.input);
16
+ }
17
+ else if (Array.isArray(payload.messages)) {
18
+ text = flattenMessages(payload.messages);
19
+ }
20
+ else if (typeof payload.prompt === "string") {
21
+ text = payload.prompt;
22
+ }
23
+ const instructions = asString(payload.instructions);
24
+ if (instructions)
25
+ text = instructions + "\n" + text;
26
+ return {
27
+ ok: true,
28
+ data: { model, text, maxOutputTokens: pickMaxOutputTokens(payload) },
29
+ };
30
+ }
31
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/extract/openai.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5E,uEAAuE;AACvE,2EAA2E;AAC3E,mDAAmD;AACnD,MAAM,UAAU,aAAa,CAC3B,OAAgC;IAEhC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,mCAAmC,CAAC,EAAE,CAAC;IACxE,CAAC;IAED,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACtC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC9C,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IACxB,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,YAAY;QAAE,IAAI,GAAG,YAAY,GAAG,IAAI,GAAG,IAAI,CAAC;IAEpD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE;KACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export type ExtractResult<T> = {
2
+ ok: true;
3
+ data: T;
4
+ } | {
5
+ ok: false;
6
+ warnings: string[];
7
+ };
8
+ export interface TextExtract {
9
+ model: string;
10
+ text: string;
11
+ maxOutputTokens?: number;
12
+ }
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/extract/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,CAAC,CAAC,IACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACrB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extract/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { ExtractResult, TextExtract } from "./types";
2
+ export declare function extractXai(payload: Record<string, unknown>): ExtractResult<TextExtract>;
3
+ //# sourceMappingURL=xai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/extract/xai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAK1D,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,aAAa,CAAC,WAAW,CAAC,CAuB5B"}
@@ -0,0 +1,30 @@
1
+ import { asString, flattenMessages, pickMaxOutputTokens } from "./messages.js";
2
+ // Accepts xai chat completions (`{model, messages}`), tokenize-text
3
+ // (`{model, text}`), or responses (`{model, input}`).
4
+ export function extractXai(payload) {
5
+ const model = asString(payload.model);
6
+ if (!model) {
7
+ return { ok: false, warnings: ["xai: payload.model is required"] };
8
+ }
9
+ let text = "";
10
+ if (typeof payload.text === "string") {
11
+ text = payload.text;
12
+ }
13
+ else if (Array.isArray(payload.messages)) {
14
+ text = flattenMessages(payload.messages);
15
+ }
16
+ else if (typeof payload.input === "string") {
17
+ text = payload.input;
18
+ }
19
+ else if (Array.isArray(payload.input)) {
20
+ text = flattenMessages(payload.input);
21
+ }
22
+ else if (typeof payload.prompt === "string") {
23
+ text = payload.prompt;
24
+ }
25
+ return {
26
+ ok: true,
27
+ data: { model, text, maxOutputTokens: pickMaxOutputTokens(payload) },
28
+ };
29
+ }
30
+ //# sourceMappingURL=xai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/extract/xai.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5E,oEAAoE;AACpE,sDAAsD;AACtD,MAAM,UAAU,UAAU,CACxB,OAAgC;IAEhC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,gCAAgC,CAAC,EAAE,CAAC;IACrE,CAAC;IAED,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC7C,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC9C,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IACxB,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE;KACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { cost } from "./cost";
2
+ export { computeEstimate } from "./compute";
3
+ export { PRICING, PRICING_AS_OF } from "./pricing/index";
4
+ export { MODEL_SLUGS, MODEL_DISPLAY, modelSlug, modelDisplay } from "./slugs";
5
+ export type { SlugProviderId, SlugModelId } from "./slugs";
6
+ export type { CostUnit, ModelPricing, PerUnitPricing, PricedProviderId, RateSource, TokenPricing, } from "./pricing/index";
7
+ export type { CostBreakdown, CostEstimate, CostProvider, CostSource, EstimateRequest, } from "./types";
8
+ export type { ExtractResult, TextExtract } from "./extract/types";
9
+ //# sourceMappingURL=index.d.ts.map