@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.
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/dist/src/compute.d.ts +3 -0
- package/dist/src/compute.d.ts.map +1 -0
- package/dist/src/compute.js +144 -0
- package/dist/src/compute.js.map +1 -0
- package/dist/src/cost.d.ts +3 -0
- package/dist/src/cost.d.ts.map +1 -0
- package/dist/src/cost.js +7 -0
- package/dist/src/cost.js.map +1 -0
- package/dist/src/extract/anthropic.d.ts +3 -0
- package/dist/src/extract/anthropic.d.ts.map +1 -0
- package/dist/src/extract/anthropic.js +26 -0
- package/dist/src/extract/anthropic.js.map +1 -0
- package/dist/src/extract/chat.d.ts +3 -0
- package/dist/src/extract/chat.d.ts.map +1 -0
- package/dist/src/extract/chat.js +29 -0
- package/dist/src/extract/chat.js.map +1 -0
- package/dist/src/extract/messages.d.ts +6 -0
- package/dist/src/extract/messages.d.ts.map +1 -0
- package/dist/src/extract/messages.js +46 -0
- package/dist/src/extract/messages.js.map +1 -0
- package/dist/src/extract/openai.d.ts +3 -0
- package/dist/src/extract/openai.d.ts.map +1 -0
- package/dist/src/extract/openai.js +31 -0
- package/dist/src/extract/openai.js.map +1 -0
- package/dist/src/extract/types.d.ts +13 -0
- package/dist/src/extract/types.d.ts.map +1 -0
- package/dist/src/extract/types.js +2 -0
- package/dist/src/extract/types.js.map +1 -0
- package/dist/src/extract/xai.d.ts +3 -0
- package/dist/src/extract/xai.d.ts.map +1 -0
- package/dist/src/extract/xai.js +30 -0
- package/dist/src/extract/xai.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/pricing/alibaba.d.ts +3 -0
- package/dist/src/pricing/alibaba.d.ts.map +1 -0
- package/dist/src/pricing/alibaba.js +16 -0
- package/dist/src/pricing/alibaba.js.map +1 -0
- package/dist/src/pricing/anthropic.d.ts +3 -0
- package/dist/src/pricing/anthropic.d.ts.map +1 -0
- package/dist/src/pricing/anthropic.js +56 -0
- package/dist/src/pricing/anthropic.js.map +1 -0
- package/dist/src/pricing/elevenlabs.d.ts +3 -0
- package/dist/src/pricing/elevenlabs.d.ts.map +1 -0
- package/dist/src/pricing/elevenlabs.js +24 -0
- package/dist/src/pricing/elevenlabs.js.map +1 -0
- package/dist/src/pricing/fireworks.d.ts +3 -0
- package/dist/src/pricing/fireworks.d.ts.map +1 -0
- package/dist/src/pricing/fireworks.js +22 -0
- package/dist/src/pricing/fireworks.js.map +1 -0
- package/dist/src/pricing/helpers.d.ts +5 -0
- package/dist/src/pricing/helpers.d.ts.map +1 -0
- package/dist/src/pricing/helpers.js +33 -0
- package/dist/src/pricing/helpers.js.map +1 -0
- package/dist/src/pricing/index.d.ts +14 -0
- package/dist/src/pricing/index.d.ts.map +1 -0
- package/dist/src/pricing/index.js +30 -0
- package/dist/src/pricing/index.js.map +1 -0
- package/dist/src/pricing/kie.d.ts +3 -0
- package/dist/src/pricing/kie.d.ts.map +1 -0
- package/dist/src/pricing/kie.js +271 -0
- package/dist/src/pricing/kie.js.map +1 -0
- package/dist/src/pricing/kimicoding.d.ts +3 -0
- package/dist/src/pricing/kimicoding.d.ts.map +1 -0
- package/dist/src/pricing/kimicoding.js +15 -0
- package/dist/src/pricing/kimicoding.js.map +1 -0
- package/dist/src/pricing/openai.d.ts +3 -0
- package/dist/src/pricing/openai.d.ts.map +1 -0
- package/dist/src/pricing/openai.js +24 -0
- package/dist/src/pricing/openai.js.map +1 -0
- package/dist/src/pricing/types.d.ts +28 -0
- package/dist/src/pricing/types.d.ts.map +1 -0
- package/dist/src/pricing/types.js +9 -0
- package/dist/src/pricing/types.js.map +1 -0
- package/dist/src/pricing/xai.d.ts +3 -0
- package/dist/src/pricing/xai.d.ts.map +1 -0
- package/dist/src/pricing/xai.js +12 -0
- package/dist/src/pricing/xai.js.map +1 -0
- package/dist/src/slugs.d.ts +231 -0
- package/dist/src/slugs.d.ts.map +1 -0
- package/dist/src/slugs.js +278 -0
- package/dist/src/slugs.js.map +1 -0
- package/dist/src/types.d.ts +30 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/src/cost.js
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extract/types.ts"],"names":[],"mappings":""}
|
|
@@ -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
|