@plurnk/plurnk-providers 0.1.0 → 0.1.2
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/README.md +7 -2
- package/SPEC.md +48 -12
- package/dist/Mock.d.ts +4 -4
- package/dist/Mock.d.ts.map +1 -1
- package/dist/Mock.js +6 -3
- package/dist/Mock.js.map +1 -1
- package/dist/OpenAICompat.d.ts +27 -0
- package/dist/OpenAICompat.d.ts.map +1 -0
- package/dist/OpenAICompat.js +79 -0
- package/dist/OpenAICompat.js.map +1 -0
- package/dist/ProviderRegistry.d.ts.map +1 -1
- package/dist/ProviderRegistry.js +8 -5
- package/dist/ProviderRegistry.js.map +1 -1
- package/dist/env.d.ts +4 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +25 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/openaiStream.d.ts +24 -0
- package/dist/openaiStream.d.ts.map +1 -0
- package/dist/openaiStream.js +103 -0
- package/dist/openaiStream.js.map +1 -0
- package/dist/standardProviders.d.ts +19 -0
- package/dist/standardProviders.d.ts.map +1 -0
- package/dist/standardProviders.js +88 -0
- package/dist/standardProviders.js.map +1 -0
- package/dist/tokenizers.d.ts +6 -0
- package/dist/tokenizers.d.ts.map +1 -0
- package/dist/tokenizers.js +36 -0
- package/dist/tokenizers.js.map +1 -0
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/usage.d.ts +21 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +42 -0
- package/dist/usage.js.map +1 -0
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -9,8 +9,13 @@ Framework + contract for `@plurnk/plurnk-providers-*` sibling packages (LLM tran
|
|
|
9
9
|
|
|
10
10
|
## Exports
|
|
11
11
|
|
|
12
|
-
- `Provider`, `ChatMessage`, `ProviderResponse`, `ProviderAssistant`, `ProviderUsage`, `ProviderFactory` — types.
|
|
13
|
-
- `parseAliasesFromEnv`, `resolveActiveAlias
|
|
12
|
+
- `Provider`, `ChatMessage`, `ProviderResponse`, `ProviderAssistant`, `ProviderUsage`, `FinishReason`, `ProviderFactory` — types.
|
|
13
|
+
- `parseAliasesFromEnv`, `resolveActiveAlias` — alias-cascade resolution (pure env-parsing). Provider instantiation (`instantiateProvider`, `loadActiveProvider`) is consumer-side; see SPEC §5.
|
|
14
|
+
- `OpenAICompatProvider` (+ `OpenAICompatConfig`, `ReasoningStyle`, `effortFromBudget`) — shared OpenAI-compatible transport spine; siblings extend it (SPEC §11).
|
|
15
|
+
- `chatCompletionStream`, `OpenAiHttpError`, `StreamResponse` — the shared SSE client.
|
|
16
|
+
- `parseRequiredInt`, `parseOptionalInt`, `requireEnv` — env helpers.
|
|
17
|
+
- `tokenizerFor`, `tokenizerByPublisher`, `parseTokenizerFamily` (+ `TokenizerFamily`, `CountTokens`) — synchronous tokenizer strategies.
|
|
18
|
+
- `STANDARD_PROVIDERS`, `isStandardProvider`, `standardProviderFromEnv` — pure-config OpenAI-compatible providers (no sibling package needed).
|
|
14
19
|
- `Mock` — reference implementation + test fixture (dual-purpose).
|
|
15
20
|
|
|
16
21
|
## Tests
|
package/SPEC.md
CHANGED
|
@@ -46,17 +46,22 @@ interface ProviderResponse {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
interface ProviderUsage {
|
|
49
|
-
prompt: number;
|
|
50
|
-
completion: number;
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
prompt: number; // input tokens (cached ones included)
|
|
50
|
+
completion: number; // visible output tokens, EXCLUDING reasoning
|
|
51
|
+
reasoning: number; // reasoning/thinking tokens, billed as output
|
|
52
|
+
cached: number; // subset of prompt served from cache
|
|
53
|
+
total: number; // prompt + completion + reasoning
|
|
53
54
|
}
|
|
54
55
|
```
|
|
55
56
|
|
|
57
|
+
Usage invariant: `total = prompt + completion + reasoning`; `cached ⊆ prompt`; `completion` excludes reasoning; **billable output = `completion + reasoning`**. Providers report reasoning two ways — inside `completion_tokens` (OpenAI, via `completion_tokens_details.reasoning_tokens`) or only as the `total − prompt − completion` gap (Gemini). The framework's `normalizeUsage` (§11) collapses both to this invariant, so siblings on `OpenAICompatProvider` get it for free.
|
|
58
|
+
|
|
56
59
|
### Promises
|
|
57
60
|
|
|
58
|
-
- `assistant.content` is the **verbatim** model emission. Consumer parses via `@plurnk/plurnk-grammar` — providers MUST NOT parse.
|
|
59
|
-
|
|
61
|
+
- `assistant.content` is the **verbatim** model emission. Consumer parses via `@plurnk/plurnk-grammar` — providers MUST NOT parse. plurnk uses a **tools-in-body** design: tool invocations are expressed as plurnk DSL *inside the message content*, never via a provider's native tool-calling API, so `content` is always raw text and providers never request, parse, or translate native tool calls.[^tools]
|
|
62
|
+
|
|
63
|
+
[^tools]: A provider that wants to drive native tool-calling (OpenAI `tool_calls`, Anthropic `tool_use`) would have to normalize those emissions back into a plurnk DSL string at the boundary. No provider does this and it is out of scope for v0 — tools-in-body sidesteps the whole problem. The clause is recorded only so a future native-tools mode has a defined contract.
|
|
64
|
+
- `assistant.usage` is authoritative and follows the invariant above. Fill `0`s when the wire response omits a breakdown.
|
|
60
65
|
- `countTokens` is **synchronous**, returns a non-negative integer, deterministic for the same input.
|
|
61
66
|
- `costFor` is **pure**, returns pico-USD non-negative integer. Returns `0` for siblings with no known rates (local Ollama, generic OpenAI-compat shims).
|
|
62
67
|
- `contextSize` resolves to `null` when provider can't determine the model's context window. Consumer treats null as "no budget info available."
|
|
@@ -78,7 +83,7 @@ class OpenAI {
|
|
|
78
83
|
}
|
|
79
84
|
```
|
|
80
85
|
|
|
81
|
-
The
|
|
86
|
+
The consumer's instantiation path calls `mod.default.fromEnv(env, alias.model)` generically (§5).
|
|
82
87
|
|
|
83
88
|
`fromEnv` MAY be sync or async; return type `Provider | Promise<Provider>`.
|
|
84
89
|
|
|
@@ -102,14 +107,20 @@ PLURNK_MODEL_opus=openrouter/anthropic/claude-opus-latest
|
|
|
102
107
|
PLURNK_MODEL=gemma
|
|
103
108
|
```
|
|
104
109
|
|
|
105
|
-
First path segment names the provider
|
|
110
|
+
First path segment names the provider; rest is the model identifier (may contain `/` for tri-level providers like openrouter's `publisher/model`).
|
|
106
111
|
|
|
107
|
-
|
|
112
|
+
This package's exported resolution surface:
|
|
108
113
|
|
|
109
114
|
- `parseAliasesFromEnv(env)` — extracts alias entries.
|
|
110
115
|
- `resolveActiveAlias(env)` — `{ alias, provider, model } | null`.
|
|
111
|
-
- `
|
|
112
|
-
|
|
116
|
+
- `standardProviderFromEnv(name, env, model)` / `isStandardProvider(name)` — tier-1 instantiation (below).
|
|
117
|
+
|
|
118
|
+
**Two-tier provider resolution.** A provider name resolves in this order:
|
|
119
|
+
|
|
120
|
+
1. **Standard provider** (`§11`) — if `isStandardProvider(name)`, the framework instantiates it directly via `standardProviderFromEnv(name, env, model)`. No sibling package exists or is imported. Covers every plain OpenAI-compatible endpoint (`openai`, `groq`, `deepseek`, `mistral`, `together`, `fireworks`, `deepinfra`, …).
|
|
121
|
+
2. **Bespoke sibling** — otherwise, dynamic-import `@plurnk/plurnk-providers-<provider>` and call `fromEnv(env, model)`. Reserved for providers with real runtime surface: a catalog/pricing probe or a non-OpenAI wire shape (`openrouter`, `ollama`, `google`, `xai`, `cloudflare`, the planned `anthropic`/`bedrock`/`vertex`/`cohere`).
|
|
122
|
+
|
|
123
|
+
Tier 1 lives here because it needs no package resolution. **Tier 2 is not shipped by this package.** Node's `import()` resolves specifiers relative to the calling module, so the dynamic-import step has to run where the sibling packages are actually installed — the consumer's `node_modules`, not this package's. The consumer owns it: in plurnk-service it is `src/core/ProviderInstantiate.ts` (`instantiateProvider` / `loadActiveProvider`). That code should try `standardProviderFromEnv` first and dynamic-import `@plurnk/plurnk-providers-<provider>` only when it returns `null`.
|
|
113
124
|
|
|
114
125
|
## §6 Engine → provider guarantees (consumer side)
|
|
115
126
|
|
|
@@ -124,7 +135,7 @@ Framework helpers (`./ProviderRegistry.ts`):
|
|
|
124
135
|
- **No DB access.** Provider never touches `node:sqlite` or storage layers.
|
|
125
136
|
- **No service access.** No imports from `@plurnk/plurnk-service`.
|
|
126
137
|
- **No grammar runtime dep.** Type-imports from `@plurnk/plurnk-grammar` are fine; invoking `PlurnkParser.parse` is consumer-side.
|
|
127
|
-
- **Raw `content`.**
|
|
138
|
+
- **Raw `content`.** Returned verbatim. Tools are expressed in-body as plurnk DSL (see §2); providers do not use native tool-calling.
|
|
128
139
|
- **Atomic.** One `generate` call resolves with one complete `ProviderResponse`. No streaming partial resolves (v0).
|
|
129
140
|
- **Honors `signal`.** Aborted calls reject; resources free; no orphaned connections.
|
|
130
141
|
- **Single model.** One provider instance speaks to one model.
|
|
@@ -180,3 +191,28 @@ A sibling package satisfies the contract when:
|
|
|
180
191
|
12. No runtime import of `@plurnk/plurnk-grammar` parser entry points.
|
|
181
192
|
|
|
182
193
|
Sibling-specific behavioral tests (wire-format compliance, model-family quirks, retry logic) live in each package's own test surface.
|
|
194
|
+
|
|
195
|
+
## §11 Shared OpenAI-compatible machinery
|
|
196
|
+
|
|
197
|
+
The framework ships the transport spine every OpenAI-compatible provider had been duplicating. Build a sibling *on top of these* — don't re-implement them.
|
|
198
|
+
|
|
199
|
+
- **`OpenAICompatProvider`** — a `Provider` implementation built by composition. Its `generate` does the universal work (merge `signal` with a `PLURNK_FETCH_TIMEOUT` deadline, stream the completion, map `usage`, normalize `finishReason` to the §2 set, assemble the response). Per-provider deltas arrive as config:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
new OpenAICompatProvider({
|
|
203
|
+
model, url, // fully-resolved chat-completions URL
|
|
204
|
+
fetchTimeoutMs,
|
|
205
|
+
headers, // fully-resolved request headers (incl. auth)
|
|
206
|
+
contextSize, // number | null
|
|
207
|
+
reasonBudget, reasoningStyle, // "none" | "think" | "include_reasoning" | "effort"
|
|
208
|
+
countTokens, costFor, // strategies; default heuristic / free
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
- **`chatCompletionStream` / `OpenAiHttpError` / `StreamResponse`** — the SSE client. One shared copy.
|
|
213
|
+
- **`normalizeUsage(raw)` / `computeCost(usage, {input, output, cached})`** — usage normalization to the §2 invariant (handles both reasoning-reporting conventions) and the single cost formula (bills `completion + reasoning` at the output rate). `OpenAICompatProvider` applies `normalizeUsage` automatically; siblings pass their per-token rates to `computeCost` in their `costFor`.
|
|
214
|
+
- **`parseRequiredInt` / `parseOptionalInt` / `requireEnv`** — env helpers; each takes a provider `label` for error prefixing.
|
|
215
|
+
- **`tokenizerFor(family)` / `tokenizerByPublisher(model, table, index)` / `parseTokenizerFamily(...)`** — synchronous tokenizer strategies (`heuristic` | `cl100k` | `llama`) and per-publisher dispatch for relay providers.
|
|
216
|
+
- **`effortFromBudget(budget)`** — the shared `PLURNK_REASON` → `low|medium|high` breakpoints.
|
|
217
|
+
|
|
218
|
+
A **bespoke sibling** therefore reduces to a thin class whose `fromEnv` probes whatever it needs (model catalog, pricing, context window), builds the config, and returns `new OpenAICompatProvider(config)`. A **standard provider** (§5 tier 1) needs no sibling at all — it's a frozen entry in `STANDARD_PROVIDERS` describing its key var, base URL, reasoning style, and tokenizer; `standardProviderFromEnv` does the rest.
|
package/dist/Mock.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { PlurnkStatement } from "@plurnk/plurnk-grammar";
|
|
2
|
-
import type { ChatMessage, Provider, ProviderAssistant, ProviderUsage } from "./types.ts";
|
|
2
|
+
import type { ChatMessage, FinishReason, Provider, ProviderAssistant, ProviderUsage } from "./types.ts";
|
|
3
3
|
export type MockAssistant = {
|
|
4
4
|
content: string;
|
|
5
5
|
reasoning: string | null;
|
|
6
|
-
usage?: ProviderUsage
|
|
7
|
-
finishReason?:
|
|
6
|
+
usage?: Partial<ProviderUsage>;
|
|
7
|
+
finishReason?: FinishReason;
|
|
8
8
|
model?: string;
|
|
9
9
|
ops?: PlurnkStatement[];
|
|
10
10
|
};
|
|
@@ -26,7 +26,7 @@ export default class Mock implements Provider {
|
|
|
26
26
|
get model(): string;
|
|
27
27
|
countTokens(text: string): number;
|
|
28
28
|
costFor(_usage: ProviderUsage): number;
|
|
29
|
-
generate(
|
|
29
|
+
generate({ signal }: {
|
|
30
30
|
messages: ChatMessage[];
|
|
31
31
|
signal?: AbortSignal;
|
|
32
32
|
}): Promise<{
|
package/dist/Mock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mock.d.ts","sourceRoot":"","sources":["../src/Mock.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Mock.d.ts","sourceRoot":"","sources":["../src/Mock.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAExG,MAAM,MAAM,aAAa,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB,KAAK,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,GAAG,CAAC,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,SAAS,EAAE,aAAa,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAGF,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG;IAAE,GAAG,CAAC,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC;AAEpF,QAAA,MAAM,aAAa,EAAE,aAA+E,CAAC;AAErG,MAAM,CAAC,OAAO,OAAO,IAAK,YAAW,QAAQ;;gBAI7B,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,YAAY,EAAE,CAAA;KAAE;IAKjG,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAA8B;IAC9D,IAAI,KAAK,IAAI,MAAM,CAAmB;IAItC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKjC,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAEhC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,qBAAqB,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC;IAkBnJ,IAAI,SAAS,IAAI,MAAM,CAA+B;CACzD;AAED,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
package/dist/Mock.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// engine tests; (b) worked example for sibling authors implementing the
|
|
5
5
|
// Provider contract. Production providers don't expose the `ops` escape
|
|
6
6
|
// hatch — that's an intg-only convenience.
|
|
7
|
-
const DEFAULT_USAGE = { prompt: 0, completion: 0, cached: 0, total: 0 };
|
|
7
|
+
const DEFAULT_USAGE = { prompt: 0, completion: 0, reasoning: 0, cached: 0, total: 0 };
|
|
8
8
|
export default class Mock {
|
|
9
9
|
#contextSize;
|
|
10
10
|
#queue;
|
|
@@ -21,7 +21,10 @@ export default class Mock {
|
|
|
21
21
|
}
|
|
22
22
|
// Mock is free.
|
|
23
23
|
costFor(_usage) { return 0; }
|
|
24
|
-
async generate(
|
|
24
|
+
async generate({ signal }) {
|
|
25
|
+
// Honor abort before consuming the queue — an aborted call makes no
|
|
26
|
+
// "wire call" and must not exhaust a queued response (SPEC §10.8).
|
|
27
|
+
signal?.throwIfAborted();
|
|
25
28
|
const next = this.#queue.shift();
|
|
26
29
|
if (next === undefined)
|
|
27
30
|
throw new Error("Mock provider exhausted: no more queued responses");
|
|
@@ -29,7 +32,7 @@ export default class Mock {
|
|
|
29
32
|
const assistant = {
|
|
30
33
|
content: a.content,
|
|
31
34
|
reasoning: a.reasoning,
|
|
32
|
-
usage: a.usage
|
|
35
|
+
usage: { ...DEFAULT_USAGE, ...a.usage },
|
|
33
36
|
finishReason: a.finishReason ?? "stop",
|
|
34
37
|
model: a.model ?? "mock",
|
|
35
38
|
...(a.ops !== undefined ? { ops: a.ops } : {}),
|
package/dist/Mock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mock.js","sourceRoot":"","sources":["../src/Mock.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,wEAAwE;AACxE,2CAA2C;
|
|
1
|
+
{"version":3,"file":"Mock.js","sourceRoot":"","sources":["../src/Mock.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,wEAAwE;AACxE,2CAA2C;AAyB3C,MAAM,aAAa,GAAkB,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAErG,MAAM,CAAC,OAAO,OAAO,IAAI;IACrB,YAAY,CAAgB;IAC5B,MAAM,CAAiB;IAEvB,YAAY,EAAE,WAAW,EAAE,SAAS,EAA6D;QAC7F,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,WAAW,KAAoB,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAC9D,IAAI,KAAK,KAAa,OAAO,MAAM,CAAC,CAAC,CAAC;IAEtC,sEAAsE;IACtE,8BAA8B;IAC9B,WAAW,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,gBAAgB;IAChB,OAAO,CAAC,MAAqB,IAAY,OAAO,CAAC,CAAC,CAAC,CAAC;IAEpD,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAqD;QACxE,oEAAoE;QACpE,mEAAmE;QACnE,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QAC7F,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QACzB,MAAM,SAAS,GAA0B;YACrC,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,KAAK,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE;YACvC,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,MAAM;YACtC,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,MAAM;YACxB,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjD,CAAC;QACF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;IAClE,CAAC;IAED,IAAI,SAAS,KAAa,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;CACzD;AAED,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ChatMessage, Provider, ProviderResponse, ProviderUsage } from "./types.ts";
|
|
2
|
+
export type ReasoningStyle = "none" | "think" | "include_reasoning" | "effort";
|
|
3
|
+
export type OpenAICompatConfig = {
|
|
4
|
+
model: string;
|
|
5
|
+
url: string;
|
|
6
|
+
fetchTimeoutMs: number;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
contextSize?: number | null;
|
|
9
|
+
reasonBudget?: number;
|
|
10
|
+
reasoningStyle?: ReasoningStyle;
|
|
11
|
+
countTokens?: (text: string) => number;
|
|
12
|
+
costFor?: (usage: ProviderUsage) => number;
|
|
13
|
+
};
|
|
14
|
+
export declare const effortFromBudget: (budget: number) => "low" | "medium" | "high";
|
|
15
|
+
export default class OpenAICompatProvider implements Provider {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(config: OpenAICompatConfig);
|
|
18
|
+
get contextSize(): number | null;
|
|
19
|
+
get model(): string;
|
|
20
|
+
countTokens(text: string): number;
|
|
21
|
+
costFor(usage: ProviderUsage): number;
|
|
22
|
+
generate({ messages, signal }: {
|
|
23
|
+
messages: ChatMessage[];
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}): Promise<ProviderResponse>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=OpenAICompat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAICompat.d.ts","sourceRoot":"","sources":["../src/OpenAICompat.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAgB,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AASvG,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,mBAAmB,GAAG,QAAQ,CAAC;AAE/E,MAAM,MAAM,kBAAkB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,CAAC;CAC9C,CAAC;AASF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,KAAK,GAAG,QAAQ,GAAG,MAIpE,CAAC;AAIF,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,QAAQ;;gBAW7C,MAAM,EAAE,kBAAkB;IAYtC,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAA8B;IAC9D,IAAI,KAAK,IAAI,MAAM,CAAwB;IAE3C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IACjC,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM;IAY/B,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAqBrH"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Shared OpenAI-compatible provider. Implements the universal generate()
|
|
2
|
+
// spine — signal merging, the SSE call, usage mapping, finishReason
|
|
3
|
+
// normalization, response assembly — that every sibling had duplicated.
|
|
4
|
+
//
|
|
5
|
+
// Composition, not inheritance: the per-provider deltas (resolved URL, auth
|
|
6
|
+
// headers, reasoning translation style, tokenizer, cost) arrive as config.
|
|
7
|
+
// A sibling's fromEnv probes whatever it needs (catalog, pricing, context
|
|
8
|
+
// window), builds the config, and returns `new OpenAICompatProvider(config)`.
|
|
9
|
+
// Pure-config providers come from ./standardProviders.ts with no sibling at all.
|
|
10
|
+
import { chatCompletionStream } from "./openaiStream.js";
|
|
11
|
+
import { normalizeUsage } from "./usage.js";
|
|
12
|
+
// SPEC §2 closed set. Wire values outside it (provider-specific or absent)
|
|
13
|
+
// collapse to null — the consumer treats null as "no signal".
|
|
14
|
+
const FINISH_REASONS = new Set(["stop", "length", "tool_calls", "content_filter"]);
|
|
15
|
+
const normalizeFinishReason = (raw) => raw !== null && FINISH_REASONS.has(raw) ? raw : null;
|
|
16
|
+
// Shared budget→effort breakpoints (xai and google had identical copies).
|
|
17
|
+
export const effortFromBudget = (budget) => {
|
|
18
|
+
if (budget <= 1000)
|
|
19
|
+
return "low";
|
|
20
|
+
if (budget <= 4000)
|
|
21
|
+
return "medium";
|
|
22
|
+
return "high";
|
|
23
|
+
};
|
|
24
|
+
const heuristicTokens = (text) => (text.length === 0 ? 0 : Math.ceil(text.length / 4));
|
|
25
|
+
export default class OpenAICompatProvider {
|
|
26
|
+
#model;
|
|
27
|
+
#url;
|
|
28
|
+
#fetchTimeoutMs;
|
|
29
|
+
#headers;
|
|
30
|
+
#contextSize;
|
|
31
|
+
#reasonBudget;
|
|
32
|
+
#reasoningStyle;
|
|
33
|
+
#countTokens;
|
|
34
|
+
#costFor;
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.#model = config.model;
|
|
37
|
+
this.#url = config.url;
|
|
38
|
+
this.#fetchTimeoutMs = config.fetchTimeoutMs;
|
|
39
|
+
this.#headers = config.headers ?? {};
|
|
40
|
+
this.#contextSize = config.contextSize ?? null;
|
|
41
|
+
this.#reasonBudget = config.reasonBudget ?? 0;
|
|
42
|
+
this.#reasoningStyle = config.reasoningStyle ?? "none";
|
|
43
|
+
this.#countTokens = config.countTokens ?? heuristicTokens;
|
|
44
|
+
this.#costFor = config.costFor ?? (() => 0);
|
|
45
|
+
}
|
|
46
|
+
get contextSize() { return this.#contextSize; }
|
|
47
|
+
get model() { return this.#model; }
|
|
48
|
+
countTokens(text) { return this.#countTokens(text); }
|
|
49
|
+
costFor(usage) { return this.#costFor(usage); }
|
|
50
|
+
#reasoningBody() {
|
|
51
|
+
if (this.#reasonBudget <= 0)
|
|
52
|
+
return {};
|
|
53
|
+
switch (this.#reasoningStyle) {
|
|
54
|
+
case "think": return { think: true };
|
|
55
|
+
case "include_reasoning": return { include_reasoning: true };
|
|
56
|
+
case "effort": return { reasoning_effort: effortFromBudget(this.#reasonBudget) };
|
|
57
|
+
case "none": return {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async generate({ messages, signal }) {
|
|
61
|
+
// Reject before any wire call when already aborted (SPEC §10.8).
|
|
62
|
+
signal?.throwIfAborted();
|
|
63
|
+
const timeoutSignal = AbortSignal.timeout(this.#fetchTimeoutMs);
|
|
64
|
+
const effectiveSignal = signal !== undefined ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
65
|
+
const body = { model: this.#model, messages, ...this.#reasoningBody() };
|
|
66
|
+
const raw = await chatCompletionStream({ url: this.#url, headers: this.#headers, body, signal: effectiveSignal });
|
|
67
|
+
return {
|
|
68
|
+
assistant: {
|
|
69
|
+
content: raw.content,
|
|
70
|
+
reasoning: raw.reasoning_content.length > 0 ? raw.reasoning_content : null,
|
|
71
|
+
usage: normalizeUsage(raw.usage),
|
|
72
|
+
finishReason: normalizeFinishReason(raw.finish_reason),
|
|
73
|
+
model: raw.model ?? this.#model,
|
|
74
|
+
},
|
|
75
|
+
assistantRaw: raw,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=OpenAICompat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAICompat.js","sourceRoot":"","sources":["../src/OpenAICompat.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderRegistry.d.ts","sourceRoot":"","sources":["../src/ProviderRegistry.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,mBAAmB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.d.ts","sourceRoot":"","sources":["../src/ProviderRegistry.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,mBAAmB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,aAAa,EAkBvF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,aAAa,GAAG,IAKzF,CAAC"}
|
package/dist/ProviderRegistry.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// env-parsing helpers.
|
|
10
10
|
export const parseAliasesFromEnv = (env = process.env) => {
|
|
11
11
|
const out = [];
|
|
12
|
+
const seen = new Set();
|
|
12
13
|
for (const [key, value] of Object.entries(env)) {
|
|
13
14
|
if (value === undefined || value.length === 0)
|
|
14
15
|
continue;
|
|
@@ -20,11 +21,13 @@ export const parseAliasesFromEnv = (env = process.env) => {
|
|
|
20
21
|
const slash = value.indexOf("/");
|
|
21
22
|
if (slash <= 0)
|
|
22
23
|
continue;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const alias = aliasRaw.toLowerCase();
|
|
25
|
+
// Aliases are case-folded, so PLURNK_MODEL_opus and PLURNK_MODEL_OPUS
|
|
26
|
+
// collide. Surface the ambiguity rather than silently picking one.
|
|
27
|
+
if (seen.has(alias))
|
|
28
|
+
throw new Error(`Duplicate provider alias "${alias}": multiple PLURNK_MODEL_* keys case-fold to the same alias. Rename one.`);
|
|
29
|
+
seen.add(alias);
|
|
30
|
+
out.push({ alias, provider: value.slice(0, slash), model: value.slice(slash + 1) });
|
|
28
31
|
}
|
|
29
32
|
return out;
|
|
30
33
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderRegistry.js","sourceRoot":"","sources":["../src/ProviderRegistry.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,kEAAkE;AAClE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,oEAAoE;AACpE,6EAA6E;AAC7E,yEAAyE;AACzE,uBAAuB;AAIvB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAmB,EAAE;IACzF,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACxD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;YAAE,SAAS;QAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,KAAK,IAAI,CAAC;YAAE,SAAS;QACzB,GAAG,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.js","sourceRoot":"","sources":["../src/ProviderRegistry.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,kEAAkE;AAClE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,oEAAoE;AACpE,6EAA6E;AAC7E,yEAAyE;AACzE,uBAAuB;AAIvB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAmB,EAAE;IACzF,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACxD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;YAAE,SAAS;QAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,KAAK,IAAI,CAAC;YAAE,SAAS;QACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACrC,sEAAsE;QACtE,mEAAmE;QACnE,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,0EAA0E,CAAC,CAAC;QACnJ,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAwB,EAAE;IAC7F,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC;IAClC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjE,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;AAC3E,CAAC,CAAC"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const parseRequiredInt: (raw: string | undefined, name: string, label: string) => number;
|
|
2
|
+
export declare const parseOptionalInt: (raw: string | undefined, name: string, label: string) => number | null;
|
|
3
|
+
export declare const requireEnv: (raw: string | undefined, name: string, label: string) => string;
|
|
4
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAKvF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAAM,GAAG,IAKhG,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAGjF,CAAC"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Env-parsing helpers shared by every provider's fromEnv factory. Each was
|
|
2
|
+
// copy-pasted per sibling with only the error-message prefix differing; the
|
|
3
|
+
// `label` parameter (the provider name) restores that prefix from one source.
|
|
4
|
+
export const parseRequiredInt = (raw, name, label) => {
|
|
5
|
+
if (raw === undefined || raw.length === 0)
|
|
6
|
+
throw new Error(`${label} provider: ${name} must be set`);
|
|
7
|
+
const n = Number(raw);
|
|
8
|
+
if (!Number.isFinite(n))
|
|
9
|
+
throw new Error(`${label} provider: ${name} must be a number (got "${raw}")`);
|
|
10
|
+
return n;
|
|
11
|
+
};
|
|
12
|
+
export const parseOptionalInt = (raw, name, label) => {
|
|
13
|
+
if (raw === undefined || raw.length === 0)
|
|
14
|
+
return null;
|
|
15
|
+
const n = Number(raw);
|
|
16
|
+
if (!Number.isFinite(n))
|
|
17
|
+
throw new Error(`${label} provider: ${name} must be a number (got "${raw}")`);
|
|
18
|
+
return n;
|
|
19
|
+
};
|
|
20
|
+
export const requireEnv = (raw, name, label) => {
|
|
21
|
+
if (raw === undefined || raw.length === 0)
|
|
22
|
+
throw new Error(`${label} provider: ${name} must be set`);
|
|
23
|
+
return raw;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAE9E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAuB,EAAE,IAAY,EAAE,KAAa,EAAU,EAAE;IAC7F,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,cAAc,CAAC,CAAC;IACrG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,2BAA2B,GAAG,IAAI,CAAC,CAAC;IACvG,OAAO,CAAC,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAuB,EAAE,IAAY,EAAE,KAAa,EAAiB,EAAE;IACpG,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,2BAA2B,GAAG,IAAI,CAAC,CAAC;IACvG,OAAO,CAAC,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAuB,EAAE,IAAY,EAAE,KAAa,EAAU,EAAE;IACvF,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,cAAc,CAAC,CAAC;IACrG,OAAO,GAAG,CAAC;AACf,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
export type { ChatMessage, Provider, ProviderAlias, ProviderAssistant, ProviderFactory, ProviderResponse, ProviderUsage, } from "./types.ts";
|
|
1
|
+
export type { ChatMessage, FinishReason, Provider, ProviderAlias, ProviderAssistant, ProviderFactory, ProviderResponse, ProviderUsage, } from "./types.ts";
|
|
2
2
|
export { parseAliasesFromEnv, resolveActiveAlias, } from "./ProviderRegistry.ts";
|
|
3
|
+
export { default as OpenAICompatProvider, effortFromBudget } from "./OpenAICompat.ts";
|
|
4
|
+
export type { OpenAICompatConfig, ReasoningStyle } from "./OpenAICompat.ts";
|
|
5
|
+
export { chatCompletionStream, OpenAiHttpError } from "./openaiStream.ts";
|
|
6
|
+
export type { StreamResponse } from "./openaiStream.ts";
|
|
7
|
+
export { parseRequiredInt, parseOptionalInt, requireEnv } from "./env.ts";
|
|
8
|
+
export { tokenizerFor, tokenizerByPublisher, parseTokenizerFamily } from "./tokenizers.ts";
|
|
9
|
+
export type { TokenizerFamily, CountTokens } from "./tokenizers.ts";
|
|
10
|
+
export { normalizeUsage, computeCost } from "./usage.ts";
|
|
11
|
+
export type { RawUsage, TokenRates } from "./usage.ts";
|
|
12
|
+
export { STANDARD_PROVIDERS, isStandardProvider, standardProviderFromEnv } from "./standardProviders.ts";
|
|
3
13
|
export { default as Mock } from "./Mock.ts";
|
|
4
14
|
export type { MockAssistant, MockResponse, MockReturnedAssistant } from "./Mock.ts";
|
|
5
15
|
export { mockDefaultUsage } from "./Mock.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,WAAW,EACX,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,aAAa,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,aAAa,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACtF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC1E,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzG,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export { parseAliasesFromEnv, resolveActiveAlias, } from "./ProviderRegistry.js";
|
|
2
|
+
// Shared OpenAI-compatible transport machinery — the spine every sibling
|
|
3
|
+
// extends and the basis for ./standardProviders.ts.
|
|
4
|
+
export { default as OpenAICompatProvider, effortFromBudget } from "./OpenAICompat.js";
|
|
5
|
+
export { chatCompletionStream, OpenAiHttpError } from "./openaiStream.js";
|
|
6
|
+
export { parseRequiredInt, parseOptionalInt, requireEnv } from "./env.js";
|
|
7
|
+
export { tokenizerFor, tokenizerByPublisher, parseTokenizerFamily } from "./tokenizers.js";
|
|
8
|
+
export { normalizeUsage, computeCost } from "./usage.js";
|
|
9
|
+
export { STANDARD_PROVIDERS, isStandardProvider, standardProviderFromEnv } from "./standardProviders.js";
|
|
2
10
|
export { default as Mock } from "./Mock.js";
|
|
3
11
|
export { mockDefaultUsage } from "./Mock.js";
|
|
4
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACH,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,uBAAuB,CAAC;AAE/B,yEAAyE;AACzE,oDAAoD;AACpD,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEtF,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE3F,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzG,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type StreamRequest = {
|
|
2
|
+
url: string;
|
|
3
|
+
headers: Record<string, string>;
|
|
4
|
+
body: Record<string, unknown>;
|
|
5
|
+
signal: AbortSignal;
|
|
6
|
+
};
|
|
7
|
+
import type { RawUsage } from "./usage.ts";
|
|
8
|
+
export type StreamResponse = {
|
|
9
|
+
model: string | null;
|
|
10
|
+
content: string;
|
|
11
|
+
reasoning_content: string;
|
|
12
|
+
finish_reason: string | null;
|
|
13
|
+
usage: RawUsage | null;
|
|
14
|
+
chunkMetadata: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
export declare class OpenAiHttpError extends Error {
|
|
17
|
+
readonly status: number;
|
|
18
|
+
readonly body: string;
|
|
19
|
+
readonly retryAfter: number | null;
|
|
20
|
+
constructor(status: number, body: string, retryAfter: number | null);
|
|
21
|
+
}
|
|
22
|
+
export declare const chatCompletionStream: ({ url, headers, body, signal }: StreamRequest) => Promise<StreamResponse>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=openaiStream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openaiStream.d.ts","sourceRoot":"","sources":["../src/openaiStream.ts"],"names":[],"mappings":"AAMA,KAAK,aAAa,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,WAAW,CAAC;CACvB,CAAC;AAEF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,MAAM,cAAc,GAAG;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C,CAAC;AAEF,qBAAa,eAAgB,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;gBACvB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;CAMtE;AAWD,eAAO,MAAM,oBAAoB,GAAU,gCAAgC,aAAa,KAAG,OAAO,CAAC,cAAc,CAmEhH,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// SSE client for OpenAI-compatible /chat/completions. Streaming keeps long
|
|
2
|
+
// completions alive through CDN proxies; the aggregated result is returned as
|
|
3
|
+
// one StreamResponse (the Provider contract is atomic — no partial resolves).
|
|
4
|
+
// Adapted from rummy's proven implementation; previously copy-pasted byte-for-
|
|
5
|
+
// byte into every @plurnk/plurnk-providers-* sibling, now shared from here.
|
|
6
|
+
export class OpenAiHttpError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
body;
|
|
9
|
+
retryAfter;
|
|
10
|
+
constructor(status, body, retryAfter) {
|
|
11
|
+
super(`OpenAI ${status} - ${body}`);
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.body = body;
|
|
14
|
+
this.retryAfter = retryAfter;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const parseRetryAfter = (header) => {
|
|
18
|
+
if (header === null)
|
|
19
|
+
return null;
|
|
20
|
+
const asInt = Number.parseInt(header, 10);
|
|
21
|
+
if (Number.isFinite(asInt))
|
|
22
|
+
return asInt * 1000;
|
|
23
|
+
const asDate = Date.parse(header);
|
|
24
|
+
if (Number.isFinite(asDate))
|
|
25
|
+
return Math.max(0, asDate - Date.now());
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
export const chatCompletionStream = async ({ url, headers, body, signal }) => {
|
|
29
|
+
const requestBody = { ...body, stream: true, stream_options: { include_usage: true } };
|
|
30
|
+
const response = await fetch(url, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
33
|
+
body: JSON.stringify(requestBody),
|
|
34
|
+
signal,
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
const errorBody = await response.text();
|
|
38
|
+
throw new OpenAiHttpError(response.status, errorBody, parseRetryAfter(response.headers.get("retry-after")));
|
|
39
|
+
}
|
|
40
|
+
if (response.body === null)
|
|
41
|
+
throw new Error("OpenAI response body is null");
|
|
42
|
+
const reader = response.body.getReader();
|
|
43
|
+
const decoder = new TextDecoder();
|
|
44
|
+
let buffer = "";
|
|
45
|
+
let content = "";
|
|
46
|
+
let reasoning_content = "";
|
|
47
|
+
let usage = null;
|
|
48
|
+
let model = null;
|
|
49
|
+
let finish_reason = null;
|
|
50
|
+
const chunkMetadata = {};
|
|
51
|
+
while (true) {
|
|
52
|
+
const { done, value } = await reader.read();
|
|
53
|
+
if (done)
|
|
54
|
+
break;
|
|
55
|
+
buffer += decoder.decode(value, { stream: true });
|
|
56
|
+
const lines = buffer.split("\n");
|
|
57
|
+
buffer = lines.pop() ?? "";
|
|
58
|
+
for (const rawLine of lines) {
|
|
59
|
+
const line = rawLine.trim();
|
|
60
|
+
if (!line.startsWith("data:"))
|
|
61
|
+
continue;
|
|
62
|
+
const payload = line.slice(5).trimStart();
|
|
63
|
+
if (payload === "[DONE]" || payload === "")
|
|
64
|
+
continue;
|
|
65
|
+
let chunk;
|
|
66
|
+
try {
|
|
67
|
+
chunk = JSON.parse(payload);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (typeof chunk.model === "string")
|
|
73
|
+
model = chunk.model;
|
|
74
|
+
if (chunk.usage !== undefined && chunk.usage !== null)
|
|
75
|
+
usage = chunk.usage;
|
|
76
|
+
for (const [k, v] of Object.entries(chunk)) {
|
|
77
|
+
if (k === "choices" || k === "usage")
|
|
78
|
+
continue;
|
|
79
|
+
chunkMetadata[k] = v;
|
|
80
|
+
}
|
|
81
|
+
const choices = chunk.choices;
|
|
82
|
+
const choice = choices?.[0];
|
|
83
|
+
if (choice === undefined)
|
|
84
|
+
continue;
|
|
85
|
+
if (typeof choice.finish_reason === "string")
|
|
86
|
+
finish_reason = choice.finish_reason;
|
|
87
|
+
const delta = choice.delta;
|
|
88
|
+
if (delta === undefined)
|
|
89
|
+
continue;
|
|
90
|
+
if (typeof delta.content === "string")
|
|
91
|
+
content += delta.content;
|
|
92
|
+
// Reasoning surfaces under different field names per provider.
|
|
93
|
+
if (typeof delta.reasoning_content === "string")
|
|
94
|
+
reasoning_content += delta.reasoning_content;
|
|
95
|
+
if (typeof delta.reasoning === "string")
|
|
96
|
+
reasoning_content += delta.reasoning;
|
|
97
|
+
if (typeof delta.thinking === "string")
|
|
98
|
+
reasoning_content += delta.thinking;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { model, content, reasoning_content, finish_reason, usage, chunkMetadata };
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=openaiStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openaiStream.js","sourceRoot":"","sources":["../src/openaiStream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Provider } from "./types.ts";
|
|
2
|
+
import { type ReasoningStyle } from "./OpenAICompat.ts";
|
|
3
|
+
import { type TokenizerFamily } from "./tokenizers.ts";
|
|
4
|
+
type StandardProviderSpec = {
|
|
5
|
+
apiKeyVar: string;
|
|
6
|
+
apiKeyRequired: boolean;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
baseUrlVar?: string;
|
|
9
|
+
chatPath: string;
|
|
10
|
+
flexBaseStrip?: boolean;
|
|
11
|
+
reasoningStyle: ReasoningStyle;
|
|
12
|
+
tokenizerDefault: TokenizerFamily;
|
|
13
|
+
tokenizerEnvVar: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const STANDARD_PROVIDERS: Readonly<Record<string, StandardProviderSpec>>;
|
|
16
|
+
export declare const isStandardProvider: (name: string) => boolean;
|
|
17
|
+
export declare const standardProviderFromEnv: (name: string, env: NodeJS.ProcessEnv, model: string) => Provider | null;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=standardProviders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standardProviders.d.ts","sourceRoot":"","sources":["../src/standardProviders.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAA6B,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,EAAsC,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE3F,KAAK,oBAAoB,GAAG;IAGxB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IAGxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,QAAQ,EAAE,MAAM,CAAC;IAIjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,eAAe,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;CAC3B,CAAC;AAGF,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAuC5E,CAAC;AAEH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,OAAqC,CAAC;AAcxF,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,CAAC,UAAU,EAAE,OAAO,MAAM,KAAG,QAAQ,GAAG,IAuBxG,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Pure-config OpenAI-compatible providers. A provider qualifies as "standard"
|
|
2
|
+
// when it has no unique runtime surface — no catalog probe, no pricing fetch,
|
|
3
|
+
// no bespoke wire shape — so it reduces to: an env var for the key, a base
|
|
4
|
+
// URL, a reasoning-translation style, and a tokenizer. Such providers need NO
|
|
5
|
+
// sibling package; the framework instantiates them directly.
|
|
6
|
+
//
|
|
7
|
+
// Two-tier resolution (SPEC §5): the consumer tries standardProviderFromEnv
|
|
8
|
+
// first, then falls back to dynamic-importing @plurnk/plurnk-providers-<name>
|
|
9
|
+
// for the bespoke ones (openrouter, ollama, google, xai, cloudflare, ...).
|
|
10
|
+
import OpenAICompatProvider from "./OpenAICompat.js";
|
|
11
|
+
import { parseRequiredInt, parseOptionalInt, requireEnv } from "./env.js";
|
|
12
|
+
import { parseTokenizerFamily, tokenizerFor } from "./tokenizers.js";
|
|
13
|
+
// Frozen so a downstream can't mutate the shared table.
|
|
14
|
+
export const STANDARD_PROVIDERS = Object.freeze({
|
|
15
|
+
// Generic OpenAI-compatible endpoint (OpenAI proper, llama-server, vLLM,
|
|
16
|
+
// LM Studio, or any chat-completions shim). Operator supplies the base.
|
|
17
|
+
// Replaces the former @plurnk/plurnk-providers-openai sibling verbatim.
|
|
18
|
+
openai: {
|
|
19
|
+
apiKeyVar: "OPENAI_API_KEY", apiKeyRequired: false,
|
|
20
|
+
baseUrlVar: "OPENAI_BASE_URL", chatPath: "/v1/chat/completions", flexBaseStrip: true,
|
|
21
|
+
reasoningStyle: "think", tokenizerDefault: "heuristic", tokenizerEnvVar: "OPENAI_TOKENIZER",
|
|
22
|
+
},
|
|
23
|
+
groq: {
|
|
24
|
+
apiKeyVar: "GROQ_API_KEY", apiKeyRequired: true,
|
|
25
|
+
baseUrl: "https://api.groq.com/openai/v1", baseUrlVar: "GROQ_BASE_URL", chatPath: "/chat/completions",
|
|
26
|
+
reasoningStyle: "effort", tokenizerDefault: "heuristic", tokenizerEnvVar: "GROQ_TOKENIZER",
|
|
27
|
+
},
|
|
28
|
+
deepseek: {
|
|
29
|
+
apiKeyVar: "DEEPSEEK_API_KEY", apiKeyRequired: true,
|
|
30
|
+
baseUrl: "https://api.deepseek.com/v1", baseUrlVar: "DEEPSEEK_BASE_URL", chatPath: "/chat/completions",
|
|
31
|
+
reasoningStyle: "none", tokenizerDefault: "heuristic", tokenizerEnvVar: "DEEPSEEK_TOKENIZER",
|
|
32
|
+
},
|
|
33
|
+
mistral: {
|
|
34
|
+
apiKeyVar: "MISTRAL_API_KEY", apiKeyRequired: true,
|
|
35
|
+
baseUrl: "https://api.mistral.ai/v1", baseUrlVar: "MISTRAL_BASE_URL", chatPath: "/chat/completions",
|
|
36
|
+
reasoningStyle: "none", tokenizerDefault: "heuristic", tokenizerEnvVar: "MISTRAL_TOKENIZER",
|
|
37
|
+
},
|
|
38
|
+
together: {
|
|
39
|
+
apiKeyVar: "TOGETHER_API_KEY", apiKeyRequired: true,
|
|
40
|
+
baseUrl: "https://api.together.xyz/v1", baseUrlVar: "TOGETHER_BASE_URL", chatPath: "/chat/completions",
|
|
41
|
+
reasoningStyle: "none", tokenizerDefault: "heuristic", tokenizerEnvVar: "TOGETHER_TOKENIZER",
|
|
42
|
+
},
|
|
43
|
+
fireworks: {
|
|
44
|
+
apiKeyVar: "FIREWORKS_API_KEY", apiKeyRequired: true,
|
|
45
|
+
baseUrl: "https://api.fireworks.ai/inference/v1", baseUrlVar: "FIREWORKS_BASE_URL", chatPath: "/chat/completions",
|
|
46
|
+
reasoningStyle: "none", tokenizerDefault: "heuristic", tokenizerEnvVar: "FIREWORKS_TOKENIZER",
|
|
47
|
+
},
|
|
48
|
+
deepinfra: {
|
|
49
|
+
apiKeyVar: "DEEPINFRA_API_KEY", apiKeyRequired: true,
|
|
50
|
+
baseUrl: "https://api.deepinfra.com/v1/openai", baseUrlVar: "DEEPINFRA_BASE_URL", chatPath: "/chat/completions",
|
|
51
|
+
reasoningStyle: "none", tokenizerDefault: "heuristic", tokenizerEnvVar: "DEEPINFRA_TOKENIZER",
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
export const isStandardProvider = (name) => name in STANDARD_PROVIDERS;
|
|
55
|
+
const resolveUrl = (spec, env, label) => {
|
|
56
|
+
const override = spec.baseUrlVar !== undefined ? env[spec.baseUrlVar] : undefined;
|
|
57
|
+
const base = override !== undefined && override.length > 0 ? override : spec.baseUrl;
|
|
58
|
+
if (base === undefined || base.length === 0) {
|
|
59
|
+
throw new Error(`${label} provider: ${spec.baseUrlVar ?? "base URL"} must be set`);
|
|
60
|
+
}
|
|
61
|
+
const trimmed = spec.flexBaseStrip === true ? base.replace(/\/v1\/?$/, "") : base.replace(/\/$/, "");
|
|
62
|
+
return `${trimmed}${spec.chatPath}`;
|
|
63
|
+
};
|
|
64
|
+
// Returns a configured Provider, or null when `name` is not a standard
|
|
65
|
+
// provider (so the consumer falls through to dynamic import).
|
|
66
|
+
export const standardProviderFromEnv = (name, env, model) => {
|
|
67
|
+
const spec = STANDARD_PROVIDERS[name];
|
|
68
|
+
if (spec === undefined)
|
|
69
|
+
return null;
|
|
70
|
+
const apiKey = spec.apiKeyRequired
|
|
71
|
+
? requireEnv(env[spec.apiKeyVar], spec.apiKeyVar, name)
|
|
72
|
+
: env[spec.apiKeyVar] ?? "";
|
|
73
|
+
const headers = {};
|
|
74
|
+
if (apiKey.length > 0)
|
|
75
|
+
headers.Authorization = `Bearer ${apiKey}`;
|
|
76
|
+
const family = parseTokenizerFamily(env[spec.tokenizerEnvVar], spec.tokenizerDefault, spec.tokenizerEnvVar, name);
|
|
77
|
+
return new OpenAICompatProvider({
|
|
78
|
+
model,
|
|
79
|
+
url: resolveUrl(spec, env, name),
|
|
80
|
+
headers,
|
|
81
|
+
contextSize: parseOptionalInt(env.PLURNK_PROVIDER_CONTEXT_SIZE, "PLURNK_PROVIDER_CONTEXT_SIZE", name),
|
|
82
|
+
fetchTimeoutMs: parseRequiredInt(env.PLURNK_FETCH_TIMEOUT, "PLURNK_FETCH_TIMEOUT", name),
|
|
83
|
+
reasonBudget: parseRequiredInt(env.PLURNK_REASON, "PLURNK_REASON", name),
|
|
84
|
+
reasoningStyle: spec.reasoningStyle,
|
|
85
|
+
countTokens: tokenizerFor(family),
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=standardProviders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standardProviders.js","sourceRoot":"","sources":["../src/standardProviders.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,6DAA6D;AAC7D,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAG3E,OAAO,oBAA6C,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAwB,MAAM,iBAAiB,CAAC;AAsB3F,wDAAwD;AACxD,MAAM,CAAC,MAAM,kBAAkB,GAAmD,MAAM,CAAC,MAAM,CAAC;IAC5F,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,EAAE;QACJ,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,KAAK;QAClD,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,sBAAsB,EAAE,aAAa,EAAE,IAAI;QACpF,cAAc,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB;KAC9F;IACD,IAAI,EAAE;QACF,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,IAAI;QAC/C,OAAO,EAAE,gCAAgC,EAAE,UAAU,EAAE,eAAe,EAAE,QAAQ,EAAE,mBAAmB;QACrG,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB;KAC7F;IACD,QAAQ,EAAE;QACN,SAAS,EAAE,kBAAkB,EAAE,cAAc,EAAE,IAAI;QACnD,OAAO,EAAE,6BAA6B,EAAE,UAAU,EAAE,mBAAmB,EAAE,QAAQ,EAAE,mBAAmB;QACtG,cAAc,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB;KAC/F;IACD,OAAO,EAAE;QACL,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,IAAI;QAClD,OAAO,EAAE,2BAA2B,EAAE,UAAU,EAAE,kBAAkB,EAAE,QAAQ,EAAE,mBAAmB;QACnG,cAAc,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB;KAC9F;IACD,QAAQ,EAAE;QACN,SAAS,EAAE,kBAAkB,EAAE,cAAc,EAAE,IAAI;QACnD,OAAO,EAAE,6BAA6B,EAAE,UAAU,EAAE,mBAAmB,EAAE,QAAQ,EAAE,mBAAmB;QACtG,cAAc,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB;KAC/F;IACD,SAAS,EAAE;QACP,SAAS,EAAE,mBAAmB,EAAE,cAAc,EAAE,IAAI;QACpD,OAAO,EAAE,uCAAuC,EAAE,UAAU,EAAE,oBAAoB,EAAE,QAAQ,EAAE,mBAAmB;QACjH,cAAc,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB;KAChG;IACD,SAAS,EAAE;QACP,SAAS,EAAE,mBAAmB,EAAE,cAAc,EAAE,IAAI;QACpD,OAAO,EAAE,qCAAqC,EAAE,UAAU,EAAE,oBAAoB,EAAE,QAAQ,EAAE,mBAAmB;QAC/G,cAAc,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB;KAChG;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,IAAI,kBAAkB,CAAC;AAExF,MAAM,UAAU,GAAG,CAAC,IAA0B,EAAE,GAAsB,EAAE,KAAa,EAAU,EAAE;IAC7F,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,MAAM,IAAI,GAAG,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;IACrF,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,IAAI,CAAC,UAAU,IAAI,UAAU,cAAc,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;AACxC,CAAC,CAAC;AAEF,uEAAuE;AACvE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,IAAY,EAAE,GAAsB,EAAE,KAAa,EAAmB,EAAE;IAC5G,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc;QAC9B,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACvD,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAEhC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,aAAa,GAAG,UAAU,MAAM,EAAE,CAAC;IAElE,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAElH,OAAO,IAAI,oBAAoB,CAAC;QAC5B,KAAK;QACL,GAAG,EAAE,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC;QAChC,OAAO;QACP,WAAW,EAAE,gBAAgB,CAAC,GAAG,CAAC,4BAA4B,EAAE,8BAA8B,EAAE,IAAI,CAAC;QACrG,cAAc,EAAE,gBAAgB,CAAC,GAAG,CAAC,oBAAoB,EAAE,sBAAsB,EAAE,IAAI,CAAC;QACxF,YAAY,EAAE,gBAAgB,CAAC,GAAG,CAAC,aAAa,EAAE,eAAe,EAAE,IAAI,CAAC;QACxE,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,WAAW,EAAE,YAAY,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;AACP,CAAC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type TokenizerFamily = "heuristic" | "cl100k" | "llama";
|
|
2
|
+
export type CountTokens = (text: string) => number;
|
|
3
|
+
export declare const tokenizerFor: (family: TokenizerFamily) => CountTokens;
|
|
4
|
+
export declare const parseTokenizerFamily: (raw: string | undefined, fallback: TokenizerFamily, envName: string, label: string) => TokenizerFamily;
|
|
5
|
+
export declare const tokenizerByPublisher: (model: string, table: ReadonlyMap<string, TokenizerFamily>, index?: number) => TokenizerFamily;
|
|
6
|
+
//# sourceMappingURL=tokenizers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizers.d.ts","sourceRoot":"","sources":["../src/tokenizers.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAQnD,eAAO,MAAM,YAAY,GAAI,QAAQ,eAAe,KAAG,WAAiC,CAAC;AAKzF,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,UAAU,eAAe,EAAE,SAAS,MAAM,EAAE,OAAO,MAAM,KAAG,eAKzH,CAAC;AAMF,eAAO,MAAM,oBAAoB,GAC7B,OAAO,MAAM,EACb,OAAO,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC3C,cAAS,KACV,eAGF,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Tokenizer strategies shared by every provider's countTokens(). Centralizes
|
|
2
|
+
// the gpt-tokenizer / llama-tokenizer-js deps (each sibling pulled them in
|
|
3
|
+
// separately) and the per-publisher dispatch maps that openrouter and
|
|
4
|
+
// cloudflare had independently re-invented.
|
|
5
|
+
//
|
|
6
|
+
// countTokens is synchronous by contract (SPEC §2), so only client-side
|
|
7
|
+
// tokenizers qualify. "heuristic" (chars/4) is the safe default for any
|
|
8
|
+
// upstream whose tokenizer we can't run locally.
|
|
9
|
+
import { encode as encodeCl100k } from "gpt-tokenizer/encoding/cl100k_base";
|
|
10
|
+
import llamaTokenizer from "llama-tokenizer-js";
|
|
11
|
+
const heuristic = (text) => (text.length === 0 ? 0 : Math.ceil(text.length / 4));
|
|
12
|
+
const cl100k = (text) => (text.length === 0 ? 0 : encodeCl100k(text).length);
|
|
13
|
+
const llama = (text) => (text.length === 0 ? 0 : llamaTokenizer.encode(text).length);
|
|
14
|
+
const STRATEGIES = Object.freeze({ heuristic, cl100k, llama });
|
|
15
|
+
export const tokenizerFor = (family) => STRATEGIES[family];
|
|
16
|
+
// Parse an operator-declared tokenizer override (e.g. OPENAI_TOKENIZER).
|
|
17
|
+
// Accepts a legacy "cl100k_base" spelling for back-compat with the openai
|
|
18
|
+
// sibling's existing env contract.
|
|
19
|
+
export const parseTokenizerFamily = (raw, fallback, envName, label) => {
|
|
20
|
+
if (raw === undefined || raw.length === 0)
|
|
21
|
+
return fallback;
|
|
22
|
+
if (raw === "cl100k_base")
|
|
23
|
+
return "cl100k";
|
|
24
|
+
if (raw === "heuristic" || raw === "cl100k" || raw === "llama")
|
|
25
|
+
return raw;
|
|
26
|
+
throw new Error(`${label} provider: ${envName} must be one of "heuristic", "cl100k", "llama" (got "${raw}")`);
|
|
27
|
+
};
|
|
28
|
+
// Dispatch a tokenizer family from a model id's publisher segment. Relay
|
|
29
|
+
// providers (openrouter, cloudflare) route across many upstream families, so
|
|
30
|
+
// the family is read from the id prefix. `index` selects which "/"-segment
|
|
31
|
+
// holds the publisher (0 for "anthropic/claude…", 1 for "@cf/meta/llama…").
|
|
32
|
+
export const tokenizerByPublisher = (model, table, index = 0) => {
|
|
33
|
+
const publisher = model.split("/")[index];
|
|
34
|
+
return publisher !== undefined ? table.get(publisher) ?? "heuristic" : "heuristic";
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=tokenizers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizers.js","sourceRoot":"","sources":["../src/tokenizers.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,2EAA2E;AAC3E,sEAAsE;AACtE,4CAA4C;AAC5C,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,iDAAiD;AAEjD,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,cAAc,MAAM,oBAAoB,CAAC;AAMhD,MAAM,SAAS,GAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AAC9F,MAAM,MAAM,GAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1F,MAAM,KAAK,GAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAElG,MAAM,UAAU,GAAmD,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAE/G,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAuB,EAAe,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAEzF,yEAAyE;AACzE,0EAA0E;AAC1E,mCAAmC;AACnC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAuB,EAAE,QAAyB,EAAE,OAAe,EAAE,KAAa,EAAmB,EAAE;IACxI,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3D,IAAI,GAAG,KAAK,aAAa;QAAE,OAAO,QAAQ,CAAC;IAC3C,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,GAAG,CAAC;IAC3E,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,cAAc,OAAO,wDAAwD,GAAG,IAAI,CAAC,CAAC;AAClH,CAAC,CAAC;AAEF,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAChC,KAAa,EACb,KAA2C,EAC3C,KAAK,GAAG,CAAC,EACM,EAAE;IACjB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;AACvF,CAAC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,14 +5,16 @@ export interface ChatMessage {
|
|
|
5
5
|
export interface ProviderUsage {
|
|
6
6
|
readonly prompt: number;
|
|
7
7
|
readonly completion: number;
|
|
8
|
+
readonly reasoning: number;
|
|
8
9
|
readonly cached: number;
|
|
9
10
|
readonly total: number;
|
|
10
11
|
}
|
|
12
|
+
export type FinishReason = "stop" | "length" | "tool_calls" | "content_filter" | null;
|
|
11
13
|
export interface ProviderAssistant {
|
|
12
14
|
readonly content: string;
|
|
13
15
|
readonly reasoning: string | null;
|
|
14
16
|
readonly usage: ProviderUsage;
|
|
15
|
-
readonly finishReason:
|
|
17
|
+
readonly finishReason: FinishReason;
|
|
16
18
|
readonly model: string;
|
|
17
19
|
}
|
|
18
20
|
export interface ProviderResponse {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACnB;AAOD,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAID,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,gBAAgB,GAAG,IAAI,CAAC;AAEtF,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,QAAQ;IACrB,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAI7F,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAGlC,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,WAAW,eAAe;IAC5B,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChF"}
|
package/dist/usage.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProviderUsage } from "./types.ts";
|
|
2
|
+
export type RawUsage = {
|
|
3
|
+
prompt_tokens?: number;
|
|
4
|
+
completion_tokens?: number;
|
|
5
|
+
total_tokens?: number;
|
|
6
|
+
cached_tokens?: number;
|
|
7
|
+
prompt_tokens_details?: {
|
|
8
|
+
cached_tokens?: number;
|
|
9
|
+
};
|
|
10
|
+
completion_tokens_details?: {
|
|
11
|
+
reasoning_tokens?: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare const normalizeUsage: (raw: RawUsage | null | undefined) => ProviderUsage;
|
|
15
|
+
export type TokenRates = {
|
|
16
|
+
input: number;
|
|
17
|
+
output: number;
|
|
18
|
+
cached: number;
|
|
19
|
+
};
|
|
20
|
+
export declare const computeCost: (usage: ProviderUsage, rates: TokenRates) => number;
|
|
21
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,MAAM,MAAM,QAAQ,GAAG;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,yBAAyB,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS,KAAG,aAsBjE,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAK3E,eAAO,MAAM,WAAW,GAAI,OAAO,aAAa,EAAE,OAAO,UAAU,KAAG,MAIrE,CAAC"}
|
package/dist/usage.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Usage normalization + cost — the shared token-accounting model.
|
|
2
|
+
//
|
|
3
|
+
// Providers report token usage in two incompatible ways:
|
|
4
|
+
// - OpenAI-style: reasoning is a SUBSET of completion_tokens, surfaced via
|
|
5
|
+
// completion_tokens_details.reasoning_tokens; total = prompt + completion.
|
|
6
|
+
// - Gemini-style: reasoning is OMITTED from completion_tokens and only
|
|
7
|
+
// recoverable as total - prompt - completion (no details field at all).
|
|
8
|
+
// normalizeUsage collapses both into one invariant (see ProviderUsage):
|
|
9
|
+
// total = prompt + completion + reasoning; cached ⊆ prompt;
|
|
10
|
+
// completion EXCLUDES reasoning; billable output = completion + reasoning.
|
|
11
|
+
export const normalizeUsage = (raw) => {
|
|
12
|
+
const prompt = raw?.prompt_tokens ?? 0;
|
|
13
|
+
const completionRaw = raw?.completion_tokens ?? 0;
|
|
14
|
+
const reportedTotal = raw?.total_tokens ?? 0;
|
|
15
|
+
// OpenAI nests cached under prompt_tokens_details; others put it top-level.
|
|
16
|
+
const cached = raw?.prompt_tokens_details?.cached_tokens ?? raw?.cached_tokens ?? 0;
|
|
17
|
+
const reasoningDetail = raw?.completion_tokens_details?.reasoning_tokens;
|
|
18
|
+
let completion;
|
|
19
|
+
let reasoning;
|
|
20
|
+
if (reasoningDetail !== undefined) {
|
|
21
|
+
// OpenAI-style: reasoning is part of completion_tokens — split it out.
|
|
22
|
+
reasoning = reasoningDetail;
|
|
23
|
+
completion = Math.max(0, completionRaw - reasoningDetail);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// Gemini-style (or no reasoning): tokens beyond prompt+completion are
|
|
27
|
+
// reasoning. Only trust the gap when a total was actually reported.
|
|
28
|
+
reasoning = reportedTotal > 0 ? Math.max(0, reportedTotal - prompt - completionRaw) : 0;
|
|
29
|
+
completion = completionRaw;
|
|
30
|
+
}
|
|
31
|
+
const total = reportedTotal > 0 ? reportedTotal : prompt + completion + reasoning;
|
|
32
|
+
return { prompt, completion, reasoning, cached, total };
|
|
33
|
+
};
|
|
34
|
+
// The one cost formula every provider uses: non-cached prompt at the input
|
|
35
|
+
// rate, cached prompt at the cache rate, and billable output (completion +
|
|
36
|
+
// reasoning) at the output rate.
|
|
37
|
+
export const computeCost = (usage, rates) => {
|
|
38
|
+
const nonCachedPrompt = Math.max(0, usage.prompt - usage.cached);
|
|
39
|
+
const output = usage.completion + usage.reasoning;
|
|
40
|
+
return Math.round(nonCachedPrompt * rates.input + usage.cached * rates.cached + output * rates.output);
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,yDAAyD;AACzD,6EAA6E;AAC7E,+EAA+E;AAC/E,yEAAyE;AACzE,4EAA4E;AAC5E,wEAAwE;AACxE,+DAA+D;AAC/D,8EAA8E;AAc9E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAgC,EAAiB,EAAE;IAC9E,MAAM,MAAM,GAAG,GAAG,EAAE,aAAa,IAAI,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,GAAG,EAAE,iBAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,GAAG,EAAE,YAAY,IAAI,CAAC,CAAC;IAC7C,4EAA4E;IAC5E,MAAM,MAAM,GAAG,GAAG,EAAE,qBAAqB,EAAE,aAAa,IAAI,GAAG,EAAE,aAAa,IAAI,CAAC,CAAC;IACpF,MAAM,eAAe,GAAG,GAAG,EAAE,yBAAyB,EAAE,gBAAgB,CAAC;IAEzE,IAAI,UAAkB,CAAC;IACvB,IAAI,SAAiB,CAAC;IACtB,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAChC,uEAAuE;QACvE,SAAS,GAAG,eAAe,CAAC;QAC5B,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,eAAe,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACJ,sEAAsE;QACtE,oEAAoE;QACpE,SAAS,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxF,UAAU,GAAG,aAAa,CAAC;IAC/B,CAAC;IACD,MAAM,KAAK,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAClF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC5D,CAAC,CAAC;AAKF,2EAA2E;AAC3E,2EAA2E;AAC3E,iCAAiC;AACjC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAoB,EAAE,KAAiB,EAAU,EAAE;IAC3E,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;AAC3G,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plurnk/plurnk-providers",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Framework + contract for the @plurnk/plurnk-providers-* LLM transport family.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"plurnk",
|
|
7
|
+
"llm",
|
|
8
|
+
"provider",
|
|
9
|
+
"tokenizer"
|
|
10
|
+
],
|
|
6
11
|
"homepage": "https://github.com/plurnk/plurnk-providers#readme",
|
|
7
12
|
"bugs": {
|
|
8
13
|
"url": "https://github.com/plurnk/plurnk-providers/issues"
|
|
@@ -41,11 +46,15 @@
|
|
|
41
46
|
"prepare": "npm run build"
|
|
42
47
|
},
|
|
43
48
|
"peerDependencies": {
|
|
44
|
-
"@plurnk/plurnk-grammar": "
|
|
49
|
+
"@plurnk/plurnk-grammar": "0.17.0"
|
|
45
50
|
},
|
|
46
51
|
"devDependencies": {
|
|
47
|
-
"@plurnk/plurnk-grammar": "
|
|
52
|
+
"@plurnk/plurnk-grammar": "0.17.0",
|
|
48
53
|
"@types/node": "^25.8.0",
|
|
49
54
|
"typescript": "^6.0.3"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"gpt-tokenizer": "^3.4.0",
|
|
58
|
+
"llama-tokenizer-js": "^1.2.2"
|
|
50
59
|
}
|
|
51
60
|
}
|