@plurnk/plurnk-providers 0.1.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 +18 -0
- package/SPEC.md +182 -0
- package/dist/Mock.d.ts +39 -0
- package/dist/Mock.d.ts.map +1 -0
- package/dist/Mock.js +42 -0
- package/dist/Mock.js.map +1 -0
- package/dist/ProviderRegistry.d.ts +4 -0
- package/dist/ProviderRegistry.d.ts.map +1 -0
- package/dist/ProviderRegistry.js +38 -0
- package/dist/ProviderRegistry.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PossumTech Laboratories
|
|
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,18 @@
|
|
|
1
|
+
# plurnk-providers
|
|
2
|
+
|
|
3
|
+
Framework + contract for `@plurnk/plurnk-providers-*` sibling packages (LLM transports + tokenizer + cost accounting). Consumed by [plurnk-service](https://github.com/plurnk/plurnk-service).
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
- [`SPEC.md`](./SPEC.md) — author-facing contract for sibling implementers.
|
|
8
|
+
- Constellation: [plurnk-grammar](https://github.com/plurnk/plurnk-grammar) (HEREDOC + AST), [plurnk-mimetypes](https://github.com/plurnk/plurnk-mimetypes), [plurnk-schemes](https://github.com/plurnk/plurnk-schemes), [plurnk-execs](https://github.com/plurnk/plurnk-execs).
|
|
9
|
+
|
|
10
|
+
## Exports
|
|
11
|
+
|
|
12
|
+
- `Provider`, `ChatMessage`, `ProviderResponse`, `ProviderAssistant`, `ProviderUsage`, `ProviderFactory` — types.
|
|
13
|
+
- `parseAliasesFromEnv`, `resolveActiveAlias`, `instantiateProvider`, `loadActiveProvider` — alias-cascade resolution and provider instantiation.
|
|
14
|
+
- `Mock` — reference implementation + test fixture (dual-purpose).
|
|
15
|
+
|
|
16
|
+
## Tests
|
|
17
|
+
|
|
18
|
+
`test:lint`, `test:unit`.
|
package/SPEC.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# plurnk-providers — Specification
|
|
2
|
+
|
|
3
|
+
Contract for `@plurnk/plurnk-providers-*` sibling packages. Audience: implementer of an LLM transport. Consumer: [plurnk-service](https://github.com/plurnk/plurnk-service) (SPEC.md §2).
|
|
4
|
+
|
|
5
|
+
## §1 Manifest
|
|
6
|
+
|
|
7
|
+
Each provider package's `package.json`:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"name": "@plurnk/plurnk-providers-<name>",
|
|
12
|
+
"plurnk": { "kind": "provider", "name": "<name>" }
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- `kind` MUST be `"provider"`.
|
|
17
|
+
- `name` is a vendor identifier (`openai`, `anthropic`, `ollama`).
|
|
18
|
+
|
|
19
|
+
Collision on `(kind: "provider", name)` at discovery: fail-hard.
|
|
20
|
+
|
|
21
|
+
## §2 Provider interface
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
interface Provider {
|
|
25
|
+
// Identity (immutable across lifetime)
|
|
26
|
+
readonly contextSize: number | null; // total context tokens, null if unresolved
|
|
27
|
+
readonly model: string; // configured model id
|
|
28
|
+
|
|
29
|
+
// Tokenomic primitives (synchronous, pure)
|
|
30
|
+
countTokens(text: string): number;
|
|
31
|
+
costFor(usage: ProviderUsage): number; // pico-USD (1e-12 USD)
|
|
32
|
+
|
|
33
|
+
// Transport
|
|
34
|
+
generate(args: { messages: ChatMessage[]; signal?: AbortSignal }): Promise<ProviderResponse>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface ProviderResponse {
|
|
38
|
+
assistant: {
|
|
39
|
+
content: string; // raw model emission; consumer parses
|
|
40
|
+
reasoning: string | null; // wire-reported CoT; null if absent
|
|
41
|
+
usage: ProviderUsage; // { prompt, completion, cached, total }
|
|
42
|
+
finishReason: "stop" | "length" | "tool_calls" | "content_filter" | null;
|
|
43
|
+
model: string; // wire-reported (may differ from requested for relay providers)
|
|
44
|
+
};
|
|
45
|
+
assistantRaw: unknown; // verbatim wire response for forensics
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ProviderUsage {
|
|
49
|
+
prompt: number;
|
|
50
|
+
completion: number;
|
|
51
|
+
cached: number;
|
|
52
|
+
total: number;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Promises
|
|
57
|
+
|
|
58
|
+
- `assistant.content` is the **verbatim** model emission. Consumer parses via `@plurnk/plurnk-grammar` — providers MUST NOT parse. Native tool-call outputs (OpenAI function calls, Anthropic tool_use) MUST be normalized back to plurnk DSL string at the provider boundary.
|
|
59
|
+
- `assistant.usage` is authoritative. Fill `0`s when the wire response omits a breakdown.
|
|
60
|
+
- `countTokens` is **synchronous**, returns a non-negative integer, deterministic for the same input.
|
|
61
|
+
- `costFor` is **pure**, returns pico-USD non-negative integer. Returns `0` for siblings with no known rates (local Ollama, generic OpenAI-compat shims).
|
|
62
|
+
- `contextSize` resolves to `null` when provider can't determine the model's context window. Consumer treats null as "no budget info available."
|
|
63
|
+
- `generate` rejects on signal abort — does NOT resolve with partial content.
|
|
64
|
+
|
|
65
|
+
## §3 `fromEnv(env, model)` factory
|
|
66
|
+
|
|
67
|
+
Default export MUST have a static `fromEnv(env, model)` factory:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
class OpenAI {
|
|
71
|
+
static fromEnv(env: NodeJS.ProcessEnv, model: string): OpenAI | Promise<OpenAI> {
|
|
72
|
+
// Read provider-specific env (OPENAI_BASE_URL, OPENAI_API_KEY, ...)
|
|
73
|
+
// plus universal operator knobs (PLURNK_REASON, PLURNK_FETCH_TIMEOUT,
|
|
74
|
+
// PLURNK_PROVIDER_CONTEXT_SIZE).
|
|
75
|
+
return new OpenAI({ /* ... */ });
|
|
76
|
+
}
|
|
77
|
+
constructor(config: OpenAIConfig) { /* ... */ }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The framework's `instantiateProvider` calls `mod.default.fromEnv(env, alias.model)` generically.
|
|
82
|
+
|
|
83
|
+
`fromEnv` MAY be sync or async; return type `Provider | Promise<Provider>`.
|
|
84
|
+
|
|
85
|
+
`fromEnv` MUST fail fast with a clear error if required env is missing — name the env var the operator needs to set.
|
|
86
|
+
|
|
87
|
+
## §4 Universal operator knobs
|
|
88
|
+
|
|
89
|
+
Each provider's `fromEnv` reads these:
|
|
90
|
+
|
|
91
|
+
- **`PLURNK_REASON`** — engine-level reasoning-token budget. Non-negative integer. Providers translate to wire format: OpenAI o-series → `reasoning_effort: low|medium|high|disabled`; llama-server / Ollama OpenAI-compat → `think: true|false`; Anthropic → `thinking: { type: "enabled", budget_tokens: n }`.
|
|
92
|
+
- **`PLURNK_FETCH_TIMEOUT`** — service-wide ms ceiling on any single outbound request. Each `fromEnv` reads and passes as `AbortSignal.timeout`. Per-provider override envs are NOT part of the contract.
|
|
93
|
+
- **`PLURNK_PROVIDER_CONTEXT_SIZE`** — optional positive-integer override for the model's reported context window. Resolution: this env var → provider probe/config/table → `null`.
|
|
94
|
+
|
|
95
|
+
## §5 Alias cascade resolution
|
|
96
|
+
|
|
97
|
+
`PLURNK_MODEL_<alias>=<provider>/<model-id>` declares an alias; `PLURNK_MODEL=<alias>` selects which is active.
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
PLURNK_MODEL_gemma=openai/macher.gguf
|
|
101
|
+
PLURNK_MODEL_opus=openrouter/anthropic/claude-opus-latest
|
|
102
|
+
PLURNK_MODEL=gemma
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
First path segment names the provider plugin (`@plurnk/plurnk-providers-<provider>`); rest is the model identifier (may contain `/` for tri-level providers like openrouter's `publisher/model`).
|
|
106
|
+
|
|
107
|
+
Framework helpers (`./ProviderRegistry.ts`):
|
|
108
|
+
|
|
109
|
+
- `parseAliasesFromEnv(env)` — extracts alias entries.
|
|
110
|
+
- `resolveActiveAlias(env)` — `{ alias, provider, model } | null`.
|
|
111
|
+
- `instantiateProvider(alias, env)` — dynamic-imports `@plurnk/plurnk-providers-<provider>` and calls `fromEnv(env, model)`.
|
|
112
|
+
- `loadActiveProvider(env)` — resolve + instantiate in one call.
|
|
113
|
+
|
|
114
|
+
## §6 Engine → provider guarantees (consumer side)
|
|
115
|
+
|
|
116
|
+
- `messages` is a complete prompt. Consumer has pre-assembled all sections. Provider does not add or reorder.
|
|
117
|
+
- `signal` is wired to the run's AbortController.
|
|
118
|
+
- `generate` is single-call per turn. No parallel calls on the same instance.
|
|
119
|
+
- `assistantRaw` is opaque to the consumer (forensics-only).
|
|
120
|
+
- `countTokens` is cheap by contract; consumer calls frequently.
|
|
121
|
+
|
|
122
|
+
## §7 Provider → engine guarantees
|
|
123
|
+
|
|
124
|
+
- **No DB access.** Provider never touches `node:sqlite` or storage layers.
|
|
125
|
+
- **No service access.** No imports from `@plurnk/plurnk-service`.
|
|
126
|
+
- **No grammar runtime dep.** Type-imports from `@plurnk/plurnk-grammar` are fine; invoking `PlurnkParser.parse` is consumer-side.
|
|
127
|
+
- **Raw `content`.** Native tool-call outputs MUST be normalized back to plurnk DSL string.
|
|
128
|
+
- **Atomic.** One `generate` call resolves with one complete `ProviderResponse`. No streaming partial resolves (v0).
|
|
129
|
+
- **Honors `signal`.** Aborted calls reject; resources free; no orphaned connections.
|
|
130
|
+
- **Single model.** One provider instance speaks to one model.
|
|
131
|
+
- **Synchronous `countTokens`, pure `costFor`.** No I/O, no async, no state beyond cached tokenizer artifacts.
|
|
132
|
+
|
|
133
|
+
## §8 Forbidden
|
|
134
|
+
|
|
135
|
+
| ❌ |
|
|
136
|
+
|---|
|
|
137
|
+
| Database access |
|
|
138
|
+
| Filesystem access beyond reading provider-internal config |
|
|
139
|
+
| Imports from `@plurnk/plurnk-service/*` |
|
|
140
|
+
| Resolving with partial content on abort |
|
|
141
|
+
| Mutating `messages` |
|
|
142
|
+
| Parsing `content` into `PlurnkStatement[]` |
|
|
143
|
+
| Streaming the resolve (atomic only; v0) |
|
|
144
|
+
| Holding state across `generate` calls beyond connection pooling and config |
|
|
145
|
+
| Reading model output via `console.*` |
|
|
146
|
+
| Ignoring `signal` |
|
|
147
|
+
| Spawning subprocesses for inference |
|
|
148
|
+
|
|
149
|
+
## §9 Reference — `Mock`
|
|
150
|
+
|
|
151
|
+
`./src/Mock.ts` — test-fixture provider + worked example. Queue of pre-built responses; `generate` shifts one off.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { Mock } from "@plurnk/plurnk-providers";
|
|
155
|
+
|
|
156
|
+
const mock = new Mock({
|
|
157
|
+
contextSize: 100000,
|
|
158
|
+
responses: [{ assistant: { content: "<<SEND[200]:hi:SEND", reasoning: null } }],
|
|
159
|
+
});
|
|
160
|
+
const result = await mock.generate({ messages: [] });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`MockResponse.assistant.ops?: PlurnkStatement[]` is a pre-parsed escape hatch consumed by plurnk-service intg tests (skips parse roundtrip). Production providers don't expose `ops`.
|
|
164
|
+
|
|
165
|
+
## §10 Conformance
|
|
166
|
+
|
|
167
|
+
A sibling package satisfies the contract when:
|
|
168
|
+
|
|
169
|
+
1. Default export is a class with `static fromEnv(env, model)` factory.
|
|
170
|
+
2. Instance exposes `contextSize: number | null` and `model: string` (non-empty).
|
|
171
|
+
3. Instance exposes `countTokens(text): number` and `costFor(usage): number`.
|
|
172
|
+
4. `countTokens("")` returns `0`; `countTokens("…")` returns a non-negative integer.
|
|
173
|
+
5. `costFor({prompt:0,completion:0,cached:0,total:0})` returns `0` (or non-negative pico-USD for non-free models).
|
|
174
|
+
6. Identity getters return stable values across reads.
|
|
175
|
+
7. `generate` resolves with a valid `ProviderResponse` shape.
|
|
176
|
+
8. `generate` invoked with a pre-aborted `signal` rejects without making a wire call.
|
|
177
|
+
9. `generate` invoked, then aborted mid-flight rejects within ≤5s; no connection leak.
|
|
178
|
+
10. `assistantRaw` is present (any value, including `null`).
|
|
179
|
+
11. No DB access, no imports from `@plurnk/plurnk-service`.
|
|
180
|
+
12. No runtime import of `@plurnk/plurnk-grammar` parser entry points.
|
|
181
|
+
|
|
182
|
+
Sibling-specific behavioral tests (wire-format compliance, model-family quirks, retry logic) live in each package's own test surface.
|
package/dist/Mock.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PlurnkStatement } from "@plurnk/plurnk-grammar";
|
|
2
|
+
import type { ChatMessage, Provider, ProviderAssistant, ProviderUsage } from "./types.ts";
|
|
3
|
+
export type MockAssistant = {
|
|
4
|
+
content: string;
|
|
5
|
+
reasoning: string | null;
|
|
6
|
+
usage?: ProviderUsage;
|
|
7
|
+
finishReason?: string | null;
|
|
8
|
+
model?: string;
|
|
9
|
+
ops?: PlurnkStatement[];
|
|
10
|
+
};
|
|
11
|
+
export type MockResponse = {
|
|
12
|
+
assistant: MockAssistant;
|
|
13
|
+
assistantRaw?: unknown;
|
|
14
|
+
};
|
|
15
|
+
export type MockReturnedAssistant = ProviderAssistant & {
|
|
16
|
+
ops?: PlurnkStatement[];
|
|
17
|
+
};
|
|
18
|
+
declare const DEFAULT_USAGE: ProviderUsage;
|
|
19
|
+
export default class Mock implements Provider {
|
|
20
|
+
#private;
|
|
21
|
+
constructor({ contextSize, responses }: {
|
|
22
|
+
contextSize: number | null;
|
|
23
|
+
responses: MockResponse[];
|
|
24
|
+
});
|
|
25
|
+
get contextSize(): number | null;
|
|
26
|
+
get model(): string;
|
|
27
|
+
countTokens(text: string): number;
|
|
28
|
+
costFor(_usage: ProviderUsage): number;
|
|
29
|
+
generate(_: {
|
|
30
|
+
messages: ChatMessage[];
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
assistant: MockReturnedAssistant;
|
|
34
|
+
assistantRaw: unknown;
|
|
35
|
+
}>;
|
|
36
|
+
get remaining(): number;
|
|
37
|
+
}
|
|
38
|
+
export { DEFAULT_USAGE as mockDefaultUsage };
|
|
39
|
+
//# sourceMappingURL=Mock.d.ts.map
|
|
@@ -0,0 +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;AAE1F,MAAM,MAAM,aAAa,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,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,aAAiE,CAAC;AAEvF,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,CAAC,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;IAe1I,IAAI,SAAS,IAAI,MAAM,CAA+B;CACzD;AAED,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
package/dist/Mock.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Mock provider — reference implementation + test fixture.
|
|
2
|
+
//
|
|
3
|
+
// Dual purpose: (a) plurnk-service intg suite uses it for deterministic
|
|
4
|
+
// engine tests; (b) worked example for sibling authors implementing the
|
|
5
|
+
// Provider contract. Production providers don't expose the `ops` escape
|
|
6
|
+
// hatch — that's an intg-only convenience.
|
|
7
|
+
const DEFAULT_USAGE = { prompt: 0, completion: 0, cached: 0, total: 0 };
|
|
8
|
+
export default class Mock {
|
|
9
|
+
#contextSize;
|
|
10
|
+
#queue;
|
|
11
|
+
constructor({ contextSize, responses }) {
|
|
12
|
+
this.#contextSize = contextSize;
|
|
13
|
+
this.#queue = [...responses];
|
|
14
|
+
}
|
|
15
|
+
get contextSize() { return this.#contextSize; }
|
|
16
|
+
get model() { return "mock"; }
|
|
17
|
+
// Heuristic tokenizer. Mock is test-only; real provider siblings ship
|
|
18
|
+
// family-specific tokenizers.
|
|
19
|
+
countTokens(text) {
|
|
20
|
+
return text.length === 0 ? 0 : Math.ceil(text.length / 4);
|
|
21
|
+
}
|
|
22
|
+
// Mock is free.
|
|
23
|
+
costFor(_usage) { return 0; }
|
|
24
|
+
async generate(_) {
|
|
25
|
+
const next = this.#queue.shift();
|
|
26
|
+
if (next === undefined)
|
|
27
|
+
throw new Error("Mock provider exhausted: no more queued responses");
|
|
28
|
+
const a = next.assistant;
|
|
29
|
+
const assistant = {
|
|
30
|
+
content: a.content,
|
|
31
|
+
reasoning: a.reasoning,
|
|
32
|
+
usage: a.usage ?? DEFAULT_USAGE,
|
|
33
|
+
finishReason: a.finishReason ?? "stop",
|
|
34
|
+
model: a.model ?? "mock",
|
|
35
|
+
...(a.ops !== undefined ? { ops: a.ops } : {}),
|
|
36
|
+
};
|
|
37
|
+
return { assistant, assistantRaw: next.assistantRaw ?? null };
|
|
38
|
+
}
|
|
39
|
+
get remaining() { return this.#queue.length; }
|
|
40
|
+
}
|
|
41
|
+
export { DEFAULT_USAGE as mockDefaultUsage };
|
|
42
|
+
//# sourceMappingURL=Mock.js.map
|
package/dist/Mock.js.map
ADDED
|
@@ -0,0 +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;AAwB3C,MAAM,aAAa,GAAkB,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAEvF,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,CAAoD;QAC/D,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,CAAC,CAAC,KAAK,IAAI,aAAa;YAC/B,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,4 @@
|
|
|
1
|
+
import type { ProviderAlias } from "./types.ts";
|
|
2
|
+
export declare const parseAliasesFromEnv: (env?: NodeJS.ProcessEnv) => ProviderAlias[];
|
|
3
|
+
export declare const resolveActiveAlias: (env?: NodeJS.ProcessEnv) => ProviderAlias | null;
|
|
4
|
+
//# sourceMappingURL=ProviderRegistry.d.ts.map
|
|
@@ -0,0 +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,EAgBvF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,aAAa,GAAG,IAKzF,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Model alias resolution. Reads PLURNK_MODEL_<alias>=<provider>/<model>
|
|
2
|
+
// env vars; PLURNK_MODEL=<alias> selects which is active at boot.
|
|
3
|
+
//
|
|
4
|
+
// `instantiateProvider` and `loadActiveProvider` (the dynamic-import path)
|
|
5
|
+
// live in the consumer (plurnk-service) because Node's `import()` resolves
|
|
6
|
+
// package specifiers relative to the calling module's location; the
|
|
7
|
+
// consumer is the package that actually has the `@plurnk/plurnk-providers-*`
|
|
8
|
+
// sibling installed in its node_modules. This module ships only the pure
|
|
9
|
+
// env-parsing helpers.
|
|
10
|
+
export const parseAliasesFromEnv = (env = process.env) => {
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const [key, value] of Object.entries(env)) {
|
|
13
|
+
if (value === undefined || value.length === 0)
|
|
14
|
+
continue;
|
|
15
|
+
if (!key.startsWith("PLURNK_MODEL_"))
|
|
16
|
+
continue;
|
|
17
|
+
const aliasRaw = key.slice("PLURNK_MODEL_".length);
|
|
18
|
+
if (aliasRaw.length === 0)
|
|
19
|
+
continue;
|
|
20
|
+
const slash = value.indexOf("/");
|
|
21
|
+
if (slash <= 0)
|
|
22
|
+
continue;
|
|
23
|
+
out.push({
|
|
24
|
+
alias: aliasRaw.toLowerCase(),
|
|
25
|
+
provider: value.slice(0, slash),
|
|
26
|
+
model: value.slice(slash + 1),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
};
|
|
31
|
+
export const resolveActiveAlias = (env = process.env) => {
|
|
32
|
+
const selected = env.PLURNK_MODEL;
|
|
33
|
+
if (selected === undefined || selected.length === 0)
|
|
34
|
+
return null;
|
|
35
|
+
const aliases = parseAliasesFromEnv(env);
|
|
36
|
+
return aliases.find((a) => a.alias === selected.toLowerCase()) ?? null;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=ProviderRegistry.js.map
|
|
@@ -0,0 +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;YACL,KAAK,EAAE,QAAQ,CAAC,WAAW,EAAE;YAC7B,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;YAC/B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;SAChC,CAAC,CAAC;IACP,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/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { ChatMessage, Provider, ProviderAlias, ProviderAssistant, ProviderFactory, ProviderResponse, ProviderUsage, } from "./types.ts";
|
|
2
|
+
export { parseAliasesFromEnv, resolveActiveAlias, } from "./ProviderRegistry.ts";
|
|
3
|
+
export { default as Mock } from "./Mock.ts";
|
|
4
|
+
export type { MockAssistant, MockResponse, MockReturnedAssistant } from "./Mock.ts";
|
|
5
|
+
export { mockDefaultUsage } from "./Mock.ts";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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;AAE/B,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
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACH,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ChatMessage {
|
|
2
|
+
role: "system" | "user" | "assistant";
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ProviderUsage {
|
|
6
|
+
readonly prompt: number;
|
|
7
|
+
readonly completion: number;
|
|
8
|
+
readonly cached: number;
|
|
9
|
+
readonly total: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ProviderAssistant {
|
|
12
|
+
readonly content: string;
|
|
13
|
+
readonly reasoning: string | null;
|
|
14
|
+
readonly usage: ProviderUsage;
|
|
15
|
+
readonly finishReason: string | null;
|
|
16
|
+
readonly model: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ProviderResponse {
|
|
19
|
+
readonly assistant: ProviderAssistant;
|
|
20
|
+
readonly assistantRaw: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface Provider {
|
|
23
|
+
generate(args: {
|
|
24
|
+
messages: ChatMessage[];
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}): Promise<ProviderResponse>;
|
|
27
|
+
readonly contextSize: number | null;
|
|
28
|
+
readonly model: string;
|
|
29
|
+
countTokens(text: string): number;
|
|
30
|
+
costFor(usage: ProviderUsage): number;
|
|
31
|
+
}
|
|
32
|
+
export interface ProviderAlias {
|
|
33
|
+
readonly alias: string;
|
|
34
|
+
readonly provider: string;
|
|
35
|
+
readonly model: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ProviderFactory {
|
|
38
|
+
fromEnv(env: NodeJS.ProcessEnv, model: string): Provider | Promise<Provider>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +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;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CAC1B;AAED,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,MAAM,GAAG,IAAI,CAAC;IACrC,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/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,2EAA2E;AAC3E,iCAAiC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@plurnk/plurnk-providers",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Framework + contract for the @plurnk/plurnk-providers-* LLM transport family.",
|
|
5
|
+
"keywords": ["plurnk", "llm", "provider", "tokenizer"],
|
|
6
|
+
"homepage": "https://github.com/plurnk/plurnk-providers#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/plurnk/plurnk-providers/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/plurnk/plurnk-providers.git"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=25"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "@wikitopian",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist/**/*",
|
|
32
|
+
"README.md",
|
|
33
|
+
"SPEC.md"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test:lint": "tsc --noEmit",
|
|
37
|
+
"test:unit": "node --test src/**/*.test.ts",
|
|
38
|
+
"test": "npm run test:lint && npm run test:unit",
|
|
39
|
+
"build:dist": "tsc -p tsconfig.build.json",
|
|
40
|
+
"build": "npm run build:dist",
|
|
41
|
+
"prepare": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@plurnk/plurnk-grammar": "^0.15.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@plurnk/plurnk-grammar": "^0.15.0",
|
|
48
|
+
"@types/node": "^25.8.0",
|
|
49
|
+
"typescript": "^6.0.3"
|
|
50
|
+
}
|
|
51
|
+
}
|