@sriinnu/kosha-discovery 1.2.0 → 1.5.1
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 +125 -52
- package/dist/aliases.d.ts +6 -1
- package/dist/aliases.d.ts.map +1 -1
- package/dist/aliases.js +38 -12
- package/dist/aliases.js.map +1 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +40 -3
- package/dist/cache.js.map +1 -1
- package/dist/claude-generation.d.ts +59 -0
- package/dist/claude-generation.d.ts.map +1 -0
- package/dist/claude-generation.js +117 -0
- package/dist/claude-generation.js.map +1 -0
- package/dist/cli-cmd-doctor.d.ts +17 -0
- package/dist/cli-cmd-doctor.d.ts.map +1 -0
- package/dist/cli-cmd-doctor.js +199 -0
- package/dist/cli-cmd-doctor.js.map +1 -0
- package/dist/cli-cmd-model.js +2 -2
- package/dist/cli-cmd-model.js.map +1 -1
- package/dist/cli-cmd-spend.d.ts +10 -0
- package/dist/cli-cmd-spend.d.ts.map +1 -0
- package/dist/cli-cmd-spend.js +130 -0
- package/dist/cli-cmd-spend.js.map +1 -0
- package/dist/cli-commands.d.ts +4 -1
- package/dist/cli-commands.d.ts.map +1 -1
- package/dist/cli-commands.js +10 -2
- package/dist/cli-commands.js.map +1 -1
- package/dist/cli-format.js.map +1 -1
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +13 -2
- package/dist/cli-help.js.map +1 -1
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/cost.d.ts +152 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +377 -0
- package/dist/cost.js.map +1 -0
- package/dist/credentials/resolver.d.ts +10 -0
- package/dist/credentials/resolver.d.ts.map +1 -1
- package/dist/credentials/resolver.js +64 -31
- package/dist/credentials/resolver.js.map +1 -1
- package/dist/discovery/anthropic.d.ts +19 -1
- package/dist/discovery/anthropic.d.ts.map +1 -1
- package/dist/discovery/anthropic.js +112 -8
- package/dist/discovery/anthropic.js.map +1 -1
- package/dist/discovery/base.d.ts +7 -0
- package/dist/discovery/base.d.ts.map +1 -1
- package/dist/discovery/base.js +32 -4
- package/dist/discovery/base.js.map +1 -1
- package/dist/discovery/bedrock.d.ts.map +1 -1
- package/dist/discovery/cerebras.d.ts.map +1 -1
- package/dist/discovery/cohere.d.ts.map +1 -1
- package/dist/discovery/deepinfra.d.ts.map +1 -1
- package/dist/discovery/deepseek.d.ts.map +1 -1
- package/dist/discovery/fireworks.d.ts.map +1 -1
- package/dist/discovery/glm.d.ts.map +1 -1
- package/dist/discovery/google.d.ts +3 -1
- package/dist/discovery/google.d.ts.map +1 -1
- package/dist/discovery/google.js +13 -6
- package/dist/discovery/google.js.map +1 -1
- package/dist/discovery/groq.d.ts.map +1 -1
- package/dist/discovery/index.d.ts +2 -0
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +6 -0
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/llama-cpp.d.ts.map +1 -1
- package/dist/discovery/lmstudio.d.ts +26 -0
- package/dist/discovery/lmstudio.d.ts.map +1 -0
- package/dist/discovery/lmstudio.js +93 -0
- package/dist/discovery/lmstudio.js.map +1 -0
- package/dist/discovery/minimax.d.ts.map +1 -1
- package/dist/discovery/mistral.d.ts.map +1 -1
- package/dist/discovery/moonshot.d.ts.map +1 -1
- package/dist/discovery/nvidia.d.ts.map +1 -1
- package/dist/discovery/ollama.d.ts.map +1 -1
- package/dist/discovery/openai-compatible.d.ts.map +1 -1
- package/dist/discovery/openai.d.ts.map +1 -1
- package/dist/discovery/openrouter.d.ts +29 -5
- package/dist/discovery/openrouter.d.ts.map +1 -1
- package/dist/discovery/openrouter.js +56 -18
- package/dist/discovery/openrouter.js.map +1 -1
- package/dist/discovery/perplexity.d.ts.map +1 -1
- package/dist/discovery/promo-overrides.js.map +1 -1
- package/dist/discovery/static-direct.d.ts +9 -1
- package/dist/discovery/static-direct.d.ts.map +1 -1
- package/dist/discovery/static-direct.js +68 -7
- package/dist/discovery/static-direct.js.map +1 -1
- package/dist/discovery/together.d.ts.map +1 -1
- package/dist/discovery/vercel.d.ts.map +1 -1
- package/dist/discovery/vertex.d.ts.map +1 -1
- package/dist/discovery/vllm.d.ts +26 -0
- package/dist/discovery/vllm.d.ts.map +1 -0
- package/dist/discovery/vllm.js +93 -0
- package/dist/discovery/vllm.js.map +1 -0
- package/dist/discovery/zai.d.ts.map +1 -1
- package/dist/discovery-contract.d.ts +7 -0
- package/dist/discovery-contract.d.ts.map +1 -1
- package/dist/discovery-contract.js.map +1 -1
- package/dist/discovery-routes.d.ts +9 -0
- package/dist/discovery-routes.d.ts.map +1 -1
- package/dist/discovery-routes.js +106 -18
- package/dist/discovery-routes.js.map +1 -1
- package/dist/enrichment/litellm.d.ts +1 -1
- package/dist/enrichment/litellm.d.ts.map +1 -1
- package/dist/enrichment/litellm.js +3 -3
- package/dist/entry.d.ts +14 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +26 -0
- package/dist/entry.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.d.ts +207 -2
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +203 -51
- package/dist/mcp-server.js.map +1 -1
- package/dist/model-features.d.ts.map +1 -1
- package/dist/model-features.js +11 -2
- package/dist/model-features.js.map +1 -1
- package/dist/normalize.d.ts +7 -7
- package/dist/normalize.js +8 -8
- package/dist/provider-catalog.d.ts.map +1 -1
- package/dist/provider-catalog.js +26 -0
- package/dist/provider-catalog.js.map +1 -1
- package/dist/proxy.d.ts +49 -7
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +754 -89
- package/dist/proxy.js.map +1 -1
- package/dist/registry-query.js +2 -2
- package/dist/registry-query.js.map +1 -1
- package/dist/registry-routing.d.ts +65 -0
- package/dist/registry-routing.d.ts.map +1 -0
- package/dist/registry-routing.js +165 -0
- package/dist/registry-routing.js.map +1 -0
- package/dist/registry-runtime.d.ts +2 -0
- package/dist/registry-runtime.d.ts.map +1 -1
- package/dist/registry-runtime.js +177 -23
- package/dist/registry-runtime.js.map +1 -1
- package/dist/registry-selection.js +6 -0
- package/dist/registry-selection.js.map +1 -1
- package/dist/registry.d.ts +69 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +133 -1
- package/dist/registry.js.map +1 -1
- package/dist/resilience.d.ts +15 -0
- package/dist/resilience.d.ts.map +1 -1
- package/dist/resilience.js +23 -1
- package/dist/resilience.js.map +1 -1
- package/dist/server.d.ts +44 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +328 -33
- package/dist/server.js.map +1 -1
- package/dist/tally.d.ts +80 -0
- package/dist/tally.d.ts.map +1 -0
- package/dist/tally.js +176 -0
- package/dist/tally.js.map +1 -0
- package/dist/types.d.ts +22 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/wire-anthropic.d.ts +264 -0
- package/dist/wire-anthropic.d.ts.map +1 -0
- package/dist/wire-anthropic.js +960 -0
- package/dist/wire-anthropic.js.map +1 -0
- package/package.json +14 -10
- package/logo.png +0 -0
package/README.md
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="logo.
|
|
2
|
+
<img src="logo.svg" alt="Kosha — AI Model Discovery" width="140" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# kosha-discovery
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<p align="center">
|
|
10
|
-
<a href="https://www.npmjs.com/package/@sriinnu/kosha-discovery"><img src="https://img.shields.io/npm/v/%40sriinnu%2Fkosha-discovery?color=7C3AED&label=npm" alt="npm version" /></a>
|
|
11
|
-
<a href="https://www.npmjs.com/package/@sriinnu/kosha-discovery"><img src="https://img.shields.io/npm/dm/%40sriinnu%2Fkosha-discovery?color=0EA5E9&label=downloads" alt="npm downloads" /></a>
|
|
12
|
-
<a href="https://github.com/sriinnu/kosha-discovery/blob/main/LICENSE"><img src="https://img.shields.io/github/license/sriinnu/kosha-discovery?color=F59E0B" alt="license" /></a>
|
|
13
|
-
<a href="https://www.npmjs.com/package/@sriinnu/kosha-discovery"><img src="https://img.shields.io/node/v/%40sriinnu%2Fkosha-discovery?color=5B21B6" alt="node version" /></a>
|
|
14
|
-
</p>
|
|
15
|
-
|
|
16
|
-
Kosha (कोश — *treasury*) discovers AI models across providers, resolves credentials, enriches with pricing, and exposes the catalog through a library, CLI, HTTP API, and a built-in OpenAI-compatible proxy. One source of truth for model identity, pricing, and routing — so your app doesn't break when providers ship new SKUs or change rates.
|
|
7
|
+
Model and provider discovery registry for LLM apps. It queries 25 provider APIs and local runtimes for their model lists, resolves credentials from env vars and CLI config files, fills in pricing and context limits from models.dev and LiteLLM, and exposes the result as a TypeScript library, a CLI, an HTTP API, an OpenAI-compatible proxy with cost tracking, and an MCP server.
|
|
17
8
|
|
|
18
9
|
## Install
|
|
19
10
|
|
|
@@ -22,6 +13,8 @@ npm install @sriinnu/kosha-discovery # library / server
|
|
|
22
13
|
npm install -g @sriinnu/kosha-discovery # global `kosha` CLI
|
|
23
14
|
```
|
|
24
15
|
|
|
16
|
+
Requires Node.js 22+.
|
|
17
|
+
|
|
25
18
|
## Quick start
|
|
26
19
|
|
|
27
20
|
### Library
|
|
@@ -31,24 +24,29 @@ import { createKosha } from "@sriinnu/kosha-discovery";
|
|
|
31
24
|
|
|
32
25
|
const kosha = await createKosha();
|
|
33
26
|
|
|
34
|
-
const models
|
|
35
|
-
const cheapest
|
|
36
|
-
const sonnet
|
|
37
|
-
console.log(sonnet
|
|
27
|
+
const models = kosha.models(); // ModelCard[] across every provider
|
|
28
|
+
const cheapest = kosha.cheapestModels({ role: "image" }); // ranked by price, with missingCredentials
|
|
29
|
+
const sonnet = kosha.model("sonnet"); // alias → canonical ID; undefined if unknown
|
|
30
|
+
console.log(sonnet?.pricing); // { inputPerMillion: 2, outputPerMillion: 10, cacheReadPerMillion: 0.2, ... }
|
|
38
31
|
```
|
|
39
32
|
|
|
40
33
|
### CLI
|
|
41
34
|
|
|
42
35
|
```bash
|
|
43
|
-
kosha discover #
|
|
44
|
-
kosha list --provider anthropic #
|
|
45
|
-
kosha model sonnet #
|
|
46
|
-
kosha
|
|
47
|
-
kosha
|
|
48
|
-
kosha
|
|
36
|
+
kosha discover # query every provider; writes ~/.kosha/cache and the manifest
|
|
37
|
+
kosha list --provider anthropic # read from the local cache
|
|
38
|
+
kosha model sonnet # one model, alias-aware
|
|
39
|
+
kosha routes claude-opus-5 # every serving route for a model (direct, OpenRouter, Bedrock, …)
|
|
40
|
+
kosha cheapest --role embeddings # rank by price for a role
|
|
41
|
+
kosha doctor --ci # deprecations + provider health; non-zero exit for CI
|
|
42
|
+
kosha spend --since 2026-09-01 # roll up the proxy's spend ledger
|
|
43
|
+
kosha refresh # bypass the cache and re-discover
|
|
44
|
+
kosha serve --port 3000 # HTTP API + proxy; binds 127.0.0.1 (see Proxy below)
|
|
49
45
|
```
|
|
50
46
|
|
|
51
|
-
|
|
47
|
+
Every command takes `--json`. `kosha --help` lists the rest.
|
|
48
|
+
|
|
49
|
+
After each discovery, a stable v1 manifest lands at `~/.kosha/registry.json`:
|
|
52
50
|
|
|
53
51
|
```bash
|
|
54
52
|
jq '.models[] | select(.pricing.inputPerMillion < 0.1) | .modelId' ~/.kosha/registry.json
|
|
@@ -57,15 +55,21 @@ jq '.models[] | select(.pricing.inputPerMillion < 0.1) | .modelId' ~/.kosha/regi
|
|
|
57
55
|
### HTTP API
|
|
58
56
|
|
|
59
57
|
```
|
|
60
|
-
GET /api/models
|
|
61
|
-
GET /api/models/:idOrAlias
|
|
62
|
-
GET /api/
|
|
63
|
-
|
|
58
|
+
GET /api/models?provider=&originProvider=&mode=&capability=
|
|
59
|
+
GET /api/models/:idOrAlias GET /api/models/:idOrAlias/routes
|
|
60
|
+
GET /api/models/cheapest?role=… GET /api/capabilities
|
|
61
|
+
GET /api/providers[/:id] GET /api/roles
|
|
62
|
+
GET /api/resolve/:alias GET /api/discovery-errors
|
|
63
|
+
GET /api/discovery[/delta|/watch|/cheapest|/binding] (stable v1 contract)
|
|
64
|
+
POST /api/refresh GET /health GET /metrics
|
|
65
|
+
GET /proxy/v1/models POST /proxy/v1/chat/completions
|
|
64
66
|
```
|
|
65
67
|
|
|
68
|
+
Parameters and response shapes: [docs/api.md](docs/api.md).
|
|
69
|
+
|
|
66
70
|
### Proxy
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
`kosha serve` also exposes an OpenAI-compatible endpoint at `/proxy/v1`. Point any OpenAI SDK at it; the proxy resolves the model or alias, picks a provider you hold credentials for, injects the upstream key, forwards the request, and writes a row to the spend ledger.
|
|
69
73
|
|
|
70
74
|
```bash
|
|
71
75
|
kosha serve # start on :3000
|
|
@@ -106,34 +110,104 @@ const routed = await client.chat.completions.create({
|
|
|
106
110
|
| `<N>k` | `128k`, `200k` | minimum context window |
|
|
107
111
|
| `provider:<id>` | `provider:groq` | pin to a specific provider |
|
|
108
112
|
|
|
109
|
-
|
|
113
|
+
`kosha:fastest`, `kosha:reliable`, and `kosha:balanced` take the same filters and rank on observed latency and circuit-breaker state instead of price.
|
|
114
|
+
|
|
115
|
+
Every response carries `x-kosha-model`, `x-kosha-provider`, `x-kosha-requested`, `x-kosha-attempt-chain`, and `x-kosha-estimated-cost-usd`; non-streaming responses add `x-kosha-actual-cost-usd` when the upstream returned a usage block.
|
|
116
|
+
|
|
117
|
+
What the proxy can forward:
|
|
118
|
+
|
|
119
|
+
| Upstream wire format | Providers | Support |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| OpenAI-compatible | OpenAI, Ollama, OpenRouter, Vercel, Groq, Together, Fireworks, DeepInfra, … | passthrough, streaming included |
|
|
122
|
+
| Anthropic Messages | Anthropic | translated: streaming, tools, `image_url`, `response_format`, `reasoning_effort`; audio input and non-function tools fail over to an OpenAI-compatible route for the same model |
|
|
123
|
+
| Cloud SDKs | Google, Bedrock, Vertex | discovery only, not proxied yet |
|
|
124
|
+
|
|
125
|
+
Defaults that matter before you expose it: the server binds `127.0.0.1`. Pass `--host 0.0.0.0` (or `KOSHA_HOST`) to listen on a network interface, and set `KOSHA_PROXY_TOKEN` so `/proxy/*` and `POST /api/refresh` require `Authorization: Bearer <token>` or `x-kosha-token`. `KOSHA_MONTHLY_BUDGET_USD` caps spend per calendar month. Reference: [docs/api.md](docs/api.md#openai-compatible-proxy), [docs/operations.md](docs/operations.md).
|
|
126
|
+
|
|
127
|
+
### MCP server
|
|
128
|
+
|
|
129
|
+
`kosha-mcp` serves the registry over the Model Context Protocol on stdio, so an agent can call `kosha_query_models`, `kosha_cheapest_model`, `kosha_ranked_routes`, `kosha_model_detail`, `kosha_model_routes`, `kosha_resolve_alias`, `kosha_provider_health`, and `kosha_context_strategy` without an HTTP server.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
claude mcp add kosha -- kosha-mcp
|
|
133
|
+
```
|
|
110
134
|
|
|
111
|
-
|
|
135
|
+
Tools and protocol details: [docs/mcp.md](docs/mcp.md).
|
|
112
136
|
|
|
113
137
|
## Supported providers
|
|
114
138
|
|
|
139
|
+
25 providers. Each has a discoverer in `src/discovery/` and a credential resolver in `src/credentials/`.
|
|
140
|
+
|
|
115
141
|
| Provider | Discovery | Credential sources |
|
|
116
142
|
|----------|-----------|--------------------|
|
|
117
|
-
| Anthropic |
|
|
118
|
-
| OpenAI |
|
|
119
|
-
| Google |
|
|
120
|
-
| AWS Bedrock | SDK → CLI → static | `AWS_ACCESS_KEY_ID`, `~/.aws/credentials`, SSO, IAM |
|
|
143
|
+
| Anthropic | `GET /v1/models` (context, output cap, capabilities read from the API) | `ANTHROPIC_API_KEY`, Claude CLI, Codex CLI |
|
|
144
|
+
| OpenAI | `GET /v1/models` | `OPENAI_API_KEY`, GitHub Copilot tokens |
|
|
145
|
+
| Google | `GET /v1beta/models` | `GOOGLE_API_KEY`, `GEMINI_API_KEY`, Gemini CLI, gcloud |
|
|
146
|
+
| AWS Bedrock | SDK → CLI → static list | `AWS_ACCESS_KEY_ID`, `~/.aws/credentials`, SSO, IAM |
|
|
121
147
|
| Vertex AI | API + gcloud | `GOOGLE_APPLICATION_CREDENTIALS`, ADC |
|
|
122
|
-
| Ollama | local API |
|
|
123
|
-
| OpenRouter | API | `OPENROUTER_API_KEY`
|
|
124
|
-
| Vercel AI Gateway |
|
|
125
|
-
| NVIDIA
|
|
126
|
-
| DeepSeek
|
|
148
|
+
| Ollama, llama.cpp, LM Studio, vLLM | local HTTP API | none |
|
|
149
|
+
| OpenRouter | API | `OPENROUTER_API_KEY` (optional; unauthenticated is rate-limited) |
|
|
150
|
+
| Vercel AI Gateway | `GET /v1/models` | `AI_GATEWAY_API_KEY`, `VERCEL_OIDC_TOKEN` (discovery works without; execution needs one) |
|
|
151
|
+
| NVIDIA, Together, Fireworks, Groq, Cerebras, Cohere, DeepInfra, Perplexity | OpenAI-compatible API | `<PROVIDER>_API_KEY` |
|
|
152
|
+
| DeepSeek, Mistral, Moonshot (Kimi), GLM (Zhipu), Z.AI, MiniMax | OpenAI-compatible API | `<PROVIDER>_API_KEY` |
|
|
127
153
|
|
|
128
|
-
|
|
154
|
+
Without a key, direct providers fall back to the public models.dev + LiteLLM catalog, then to a curated static list, so `kosha list` works on a fresh machine. Exact env var names: [docs/credentials.md](docs/credentials.md).
|
|
129
155
|
|
|
130
|
-
##
|
|
156
|
+
## How it works
|
|
131
157
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
158
|
+
1. **Discovery** — one discoverer per provider runs concurrently (`Promise.allSettled`); each returns normalized `ModelCard`s. A failing provider is recorded in `discoveryErrors()` and doesn't block the others.
|
|
159
|
+
2. **Enrichment** — pricing, context window, and output cap are filled from models.dev and LiteLLM where the provider API doesn't publish them; `pricingSource` on each card says which.
|
|
160
|
+
3. **Resilience** — a per-provider circuit breaker with exponential cooldown, plus stale-cache fallback, so a provider outage degrades to cached data rather than an error.
|
|
161
|
+
4. **Cache and manifest** — results are cached under `~/.kosha/cache/` (24 h TTL) and exported as a versioned snapshot at `~/.kosha/registry.json` for other tools to read.
|
|
162
|
+
5. **Proxy** — resolves the requested model or `kosha:<strategy>[filters]` selector against the registry, ranks candidate routes, forwards with failover, and records estimated and reconciled cost in `~/.kosha/ledger-YYYY-MM.jsonl`.
|
|
163
|
+
|
|
164
|
+
Details: [docs/architecture.md](docs/architecture.md), [docs/resilience.md](docs/resilience.md).
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
pnpm install
|
|
170
|
+
pnpm run build # compile to dist/
|
|
171
|
+
pnpm run typecheck # tsc --noEmit
|
|
172
|
+
pnpm run lint # biome lint
|
|
173
|
+
pnpm test # vitest run
|
|
174
|
+
pnpm run check # lint + build + test
|
|
175
|
+
```
|
|
135
176
|
|
|
136
|
-
|
|
177
|
+
### Project layout
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
src/
|
|
181
|
+
cli.ts # CLI entry point and arg parsing
|
|
182
|
+
cli-commands.ts # command implementations (+ cli-cmd-*.ts for the larger ones)
|
|
183
|
+
registry.ts # ModelRegistry public API
|
|
184
|
+
registry-runtime.ts # discovery orchestration, enrichment, cache, manifest export
|
|
185
|
+
registry-query.ts # model / role / capability queries
|
|
186
|
+
registry-selection.ts # cheapest candidates, binding hints
|
|
187
|
+
registry-routing.ts # cheapest / fastest / reliable / balanced ranking
|
|
188
|
+
discovery/ # one discoverer per provider + static and public-seed catalogs
|
|
189
|
+
enrichment/ # models.dev + LiteLLM pricing enrichment
|
|
190
|
+
credentials/ # credential resolution (env, CLI files, ADC, OAuth)
|
|
191
|
+
provider-catalog.ts # provider descriptors: base URLs, transport, env var names
|
|
192
|
+
aliases.ts # built-in short names → canonical model IDs
|
|
193
|
+
claude-generation.ts # which Claude generation accepts which API parameters
|
|
194
|
+
model-features.ts # tool dialect / structured-output inference per model
|
|
195
|
+
proxy.ts # OpenAI-compatible proxy: routing, failover, ledger
|
|
196
|
+
wire-anthropic.ts # OpenAI ↔ Anthropic request / response / SSE translation
|
|
197
|
+
cost.ts # spend ledger, budget gates, usage reconciliation
|
|
198
|
+
tally.ts # zero-dependency token usage + USD tally (also exported as ./tally)
|
|
199
|
+
server.ts # Hono HTTP API + operator token gate
|
|
200
|
+
mcp-server.ts # MCP stdio server
|
|
201
|
+
types.ts # shared types
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Adding a provider
|
|
205
|
+
|
|
206
|
+
1. Add a descriptor to `PROVIDER_CATALOG` in `src/provider-catalog.ts` (id, base URL, transport, credential env vars).
|
|
207
|
+
2. Create `src/discovery/<provider>.ts` extending `BaseDiscoverer`; `fetchJSON` and `makeCard` are provided.
|
|
208
|
+
3. Export it from `src/discovery/index.ts` and add a factory entry to `DISCOVERER_REGISTRY` in the same file.
|
|
209
|
+
4. If the provider needs more than a single env var, add a resolver branch in `src/credentials/resolver.ts`.
|
|
210
|
+
5. Add `test/discovery/<provider>.test.ts` (mock `fetch`; see `anthropic.test.ts`) and document the env vars in `docs/credentials.md`.
|
|
137
211
|
|
|
138
212
|
## Docs
|
|
139
213
|
|
|
@@ -142,26 +216,25 @@ Discovery layer talks to provider APIs and local catalogs. Enrichment layer fill
|
|
|
142
216
|
| [Credentials](docs/credentials.md) | Env vars, CLI tools, and config files for every provider |
|
|
143
217
|
| [CLI](docs/cli.md) | Commands, flags, examples |
|
|
144
218
|
| [HTTP API](docs/api.md) | Endpoints, parameters, response schemas |
|
|
219
|
+
| [MCP server](docs/mcp.md) | Tools, protocol negotiation, client setup |
|
|
145
220
|
| [Configuration](docs/configuration.md) | Aliases, routing, enrichment, programmatic config |
|
|
146
221
|
| [Architecture](docs/architecture.md) | Discovery flow, module map, adding providers |
|
|
147
222
|
| [Resilience](docs/resilience.md) | Circuit breakers, stale cache, health |
|
|
223
|
+
| [Operations](docs/operations.md) | Deployment sizing, metrics, spend ledger, recovery recipes |
|
|
148
224
|
| [Security](docs/security.md) | Threat catalogue, runtime scanning, pre-commit hook |
|
|
149
225
|
| [Discovery Plane v1](docs/discovery-plane-v1.md) | Stable daemon contract (deltas, SSE watch, binding hints) |
|
|
150
226
|
|
|
151
227
|
## Release
|
|
152
228
|
|
|
153
|
-
|
|
229
|
+
1. Bump `version` in `package.json` and date the `[Unreleased]` section in `CHANGELOG.md`; merge that as a PR.
|
|
230
|
+
2. Tag and push:
|
|
154
231
|
|
|
155
232
|
```bash
|
|
156
233
|
git tag -s vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z
|
|
157
|
-
|
|
234
|
+
gh workflow run release-npm.yml -f tag=vX.Y.Z
|
|
158
235
|
```
|
|
159
236
|
|
|
160
|
-
The workflow checks tag
|
|
161
|
-
|
|
162
|
-
## Credits
|
|
163
|
-
|
|
164
|
-
[litellm](https://github.com/BerriAI/litellm) (pricing data) · [openrouter](https://openrouter.ai) · [ollama](https://ollama.ai) · [chitragupta](https://github.com/sriinnu/chitragupta) (registry patterns) · [takumi](https://github.com/sriinnu/takumi) (routing needs that drove kosha's creation).
|
|
237
|
+
The workflow checks that the tag matches `package.json`, runs lint / build / test, publishes to npm with provenance, and creates the GitHub Release. Publishing authenticates through npm trusted publishing (OIDC) when a trusted publisher is configured for this repo and workflow on npmjs.com, or through an `NPM_TOKEN` repository secret.
|
|
165
238
|
|
|
166
239
|
## License
|
|
167
240
|
|
package/dist/aliases.d.ts
CHANGED
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
* Curated default aliases mapping short names to canonical model IDs.
|
|
10
10
|
*
|
|
11
11
|
* These are production-ready and cover the most commonly referenced
|
|
12
|
-
* models across major providers. Updated
|
|
12
|
+
* models across major providers. Updated September 2026.
|
|
13
|
+
*
|
|
14
|
+
* Convention: a bare family name (`opus`, `sonnet`, `gemini-pro`) always
|
|
15
|
+
* tracks the newest generally-available model in that family; a suffixed
|
|
16
|
+
* form (`opus-4.8`, `sonnet-4`) pins a generation and is kept for
|
|
17
|
+
* backward compatibility when the bare alias moves on.
|
|
13
18
|
*/
|
|
14
19
|
export declare const DEFAULT_ALIASES: Readonly<Record<string, string>>;
|
|
15
20
|
/**
|
package/dist/aliases.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH
|
|
1
|
+
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsE5D,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,aAAa;IACzB,sEAAsE;IACtE,OAAO,CAAC,OAAO,CAAsB;IAErC;;;OAGG;IACH,YAAY,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAQjD;IAED;;;OAGG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEnC;IAED;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQxC;IAED;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;IAED;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/B;IAED;;OAEG;IACH,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE5B;CACD"}
|
package/dist/aliases.js
CHANGED
|
@@ -9,27 +9,53 @@
|
|
|
9
9
|
* Curated default aliases mapping short names to canonical model IDs.
|
|
10
10
|
*
|
|
11
11
|
* These are production-ready and cover the most commonly referenced
|
|
12
|
-
* models across major providers. Updated
|
|
12
|
+
* models across major providers. Updated September 2026.
|
|
13
|
+
*
|
|
14
|
+
* Convention: a bare family name (`opus`, `sonnet`, `gemini-pro`) always
|
|
15
|
+
* tracks the newest generally-available model in that family; a suffixed
|
|
16
|
+
* form (`opus-4.8`, `sonnet-4`) pins a generation and is kept for
|
|
17
|
+
* backward compatibility when the bare alias moves on.
|
|
13
18
|
*/
|
|
14
19
|
export const DEFAULT_ALIASES = {
|
|
15
|
-
// ── Anthropic — Claude
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
// ── Anthropic — Claude 5 family (latest as of Sep 2026) ──
|
|
21
|
+
// Bare IDs, never date-suffixed: `claude-haiku-4-5` is the canonical
|
|
22
|
+
// form; the dated `claude-haiku-4-5-20251001` snapshot still resolves via
|
|
23
|
+
// normalizeModelId() for callers that pinned it.
|
|
24
|
+
"fable": "claude-fable-5-1",
|
|
25
|
+
"fable-5.1": "claude-fable-5-1",
|
|
26
|
+
"fable-5": "claude-fable-5",
|
|
27
|
+
"mythos": "claude-mythos-5-1",
|
|
28
|
+
"mythos-5.1": "claude-mythos-5-1",
|
|
29
|
+
"opus": "claude-opus-5",
|
|
30
|
+
"opus-5": "claude-opus-5",
|
|
31
|
+
"opus-4": "claude-opus-4-8",
|
|
32
|
+
"opus-4.8": "claude-opus-4-8",
|
|
33
|
+
"opus-4.7": "claude-opus-4-7",
|
|
34
|
+
"sonnet": "claude-sonnet-5",
|
|
35
|
+
"sonnet-5": "claude-sonnet-5",
|
|
19
36
|
"sonnet-4": "claude-sonnet-4-6",
|
|
20
|
-
"
|
|
21
|
-
"haiku
|
|
22
|
-
|
|
37
|
+
"sonnet-4.6": "claude-sonnet-4-6",
|
|
38
|
+
"haiku": "claude-haiku-4-5",
|
|
39
|
+
"haiku-4.5": "claude-haiku-4-5",
|
|
40
|
+
// ── OpenAI — GPT-5 family, GPT-4o, and o-series reasoning ──
|
|
41
|
+
"gpt5": "gpt-5",
|
|
42
|
+
"gpt5-mini": "gpt-5-mini",
|
|
43
|
+
"gpt5-nano": "gpt-5-nano",
|
|
44
|
+
"gpt5-pro": "gpt-5-pro",
|
|
45
|
+
"gpt4.1": "gpt-4.1",
|
|
23
46
|
"gpt4o": "gpt-4o",
|
|
24
47
|
"gpt4o-mini": "gpt-4o-mini",
|
|
25
48
|
"o1": "o1",
|
|
26
49
|
"o3": "o3",
|
|
27
50
|
"o3-mini": "o3-mini",
|
|
28
51
|
"o4-mini": "o4-mini",
|
|
29
|
-
// ── Google — Gemini 2.5
|
|
30
|
-
"gemini-pro": "gemini-2.5-pro
|
|
31
|
-
"gemini-flash": "gemini-2.5-flash
|
|
32
|
-
"gemini-flash-lite": "gemini-2.
|
|
52
|
+
// ── Google — Gemini 2.5 GA IDs (the dated -preview- IDs are retired) ──
|
|
53
|
+
"gemini-pro": "gemini-2.5-pro",
|
|
54
|
+
"gemini-flash": "gemini-2.5-flash",
|
|
55
|
+
"gemini-flash-lite": "gemini-2.5-flash-lite",
|
|
56
|
+
// ── Moonshot — Kimi family ──
|
|
57
|
+
"kimi": "kimi-k3",
|
|
58
|
+
"kimi-k3": "kimi-k3",
|
|
33
59
|
// ── Local — latest popular open-weight models for Ollama ──
|
|
34
60
|
"qwen": "qwen3:8b",
|
|
35
61
|
"llama": "llama3.3:latest",
|
package/dist/aliases.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aliases.js","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH
|
|
1
|
+
{"version":3,"file":"aliases.js","sourceRoot":"","sources":["../src/aliases.ts"],"names":[],"mappings":"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"}
|
package/dist/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,UAAU,UAAU,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,UAAU,UAAU,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;CAClB;AAqBD;;;;;GAKG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC,YAAY,QAAQ,CAAC,EAAE,MAAM,EAE5B;IAED;;;OAGG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAsCvD;IAED;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAehD;IAED;;OAEG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3C;IAED;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAU3B;IAED;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;IAMD;;;OAGG;IACH,OAAO,CAAC,SAAS;IAKjB;;OAEG;YACW,SAAS;CAGvB"}
|
package/dist/cache.js
CHANGED
|
@@ -6,11 +6,28 @@
|
|
|
6
6
|
* Each cache key maps to a `{key}.json` file inside the cache directory.
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import { mkdir,
|
|
9
|
+
import { mkdir, open, readdir, rename, unlink, writeFile } from "fs/promises";
|
|
10
10
|
import { randomBytes } from "crypto";
|
|
11
11
|
import { homedir } from "os";
|
|
12
12
|
import { join } from "path";
|
|
13
13
|
import { assertCleanPayload } from "./security.js";
|
|
14
|
+
/**
|
|
15
|
+
* Hard ceiling on a single cache file before we even attempt to parse it.
|
|
16
|
+
* A legitimate full-registry snapshot is a few hundred KB; anything past
|
|
17
|
+
* this is either corruption or a hostile payload crafted to exhaust memory
|
|
18
|
+
* (a "JSON bomb"). We reject it as a cache miss rather than feeding it to
|
|
19
|
+
* `JSON.parse`, which buffers and parses the whole string eagerly.
|
|
20
|
+
*/
|
|
21
|
+
const MAX_CACHE_FILE_BYTES = 25 * 1024 * 1024;
|
|
22
|
+
/**
|
|
23
|
+
* Strip CR/LF (and other control chars) from a cache key before it is
|
|
24
|
+
* interpolated into a log line. A key can derive from a CLI/HTTP-supplied
|
|
25
|
+
* provider id (`provider_<id>`), so logging it verbatim would let crafted
|
|
26
|
+
* input forge extra log records (log injection / CWE-117).
|
|
27
|
+
*/
|
|
28
|
+
function sanitizeKeyForLog(key) {
|
|
29
|
+
return key.replace(/[\r\n\t]/g, "").slice(0, 200);
|
|
30
|
+
}
|
|
14
31
|
/**
|
|
15
32
|
* Simple file-based JSON cache with TTL support.
|
|
16
33
|
* Stores discovered provider data to avoid re-fetching on every startup.
|
|
@@ -27,9 +44,26 @@ export class KoshaCache {
|
|
|
27
44
|
* Returns null if the entry is missing or the file cannot be read.
|
|
28
45
|
*/
|
|
29
46
|
async get(key) {
|
|
47
|
+
let handle;
|
|
30
48
|
try {
|
|
31
49
|
const filePath = this.keyToPath(key);
|
|
32
|
-
|
|
50
|
+
// Stat and read through the SAME open file descriptor rather than
|
|
51
|
+
// by path. fstat() on an fd reflects exactly the bytes the
|
|
52
|
+
// following read will see, so a rename/replace of the path in the
|
|
53
|
+
// gap between a path-based stat() and a path-based readFile()
|
|
54
|
+
// can't smuggle a file past the size guard below (CodeQL
|
|
55
|
+
// js/file-system-race; the fd-bound fstat+read pair has no such
|
|
56
|
+
// gap — the descriptor stays pinned to one inode).
|
|
57
|
+
handle = await open(filePath, "r");
|
|
58
|
+
const { size } = await handle.stat();
|
|
59
|
+
if (size > MAX_CACHE_FILE_BYTES) {
|
|
60
|
+
console.warn(`KoshaCache: cache file for key "${sanitizeKeyForLog(key)}" is ${size} bytes (> ${MAX_CACHE_FILE_BYTES}); refusing to parse and invalidating`);
|
|
61
|
+
await handle.close();
|
|
62
|
+
handle = undefined;
|
|
63
|
+
await this.invalidate(key);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const raw = await handle.readFile("utf-8");
|
|
33
67
|
const entry = JSON.parse(raw);
|
|
34
68
|
assertCleanPayload(entry, `cache/${key}`);
|
|
35
69
|
return entry;
|
|
@@ -41,10 +75,13 @@ export class KoshaCache {
|
|
|
41
75
|
await this.invalidate(key);
|
|
42
76
|
}
|
|
43
77
|
else if (err instanceof SyntaxError) {
|
|
44
|
-
console.warn(`KoshaCache: corrupted cache file for key "${key}"`);
|
|
78
|
+
console.warn(`KoshaCache: corrupted cache file for key "${sanitizeKeyForLog(key)}"`);
|
|
45
79
|
}
|
|
46
80
|
return null;
|
|
47
81
|
}
|
|
82
|
+
finally {
|
|
83
|
+
await handle?.close().catch(() => { });
|
|
84
|
+
}
|
|
48
85
|
}
|
|
49
86
|
/**
|
|
50
87
|
* Write data to the cache under the given key.
|
package/dist/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — Claude generation parsing and per-generation behaviour.
|
|
3
|
+
*
|
|
4
|
+
* One source of truth for "which Claude is this and what does it accept",
|
|
5
|
+
* shared by the catalog feature inference (`model-features.ts`) and the
|
|
6
|
+
* proxy's wire translator (`wire-anthropic.ts`). Keeping it in one module
|
|
7
|
+
* means an OpenRouter-style `anthropic/claude-sonnet-4.6`, a Bedrock-style
|
|
8
|
+
* `anthropic.claude-opus-4-8-v1:0`, and the bare `claude-opus-4-8` all
|
|
9
|
+
* classify identically everywhere.
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
export interface ClaudeGeneration {
|
|
13
|
+
family: "opus" | "sonnet" | "haiku" | "fable" | "mythos";
|
|
14
|
+
major: number;
|
|
15
|
+
minor: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse the generation out of a family-first Claude ID such as
|
|
19
|
+
* `claude-opus-4-8`, `claude-sonnet-5`, `claude-fable-5-1`, a dated
|
|
20
|
+
* `claude-haiku-4-5-20251001`, or a prefixed / dotted variant. Legacy
|
|
21
|
+
* version-first IDs (`claude-3-5-sonnet-…`, `claude-2.1`) and non-Claude IDs
|
|
22
|
+
* return `undefined`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseClaudeGeneration(modelId: string): ClaudeGeneration | undefined;
|
|
25
|
+
/** How a Claude model treats `temperature` / `top_p`. */
|
|
26
|
+
export type SamplingSupport = "both" | "one" | "none";
|
|
27
|
+
/**
|
|
28
|
+
* Sampling parameters were removed on Opus 4.7 and every later model (Opus
|
|
29
|
+
* 4.8, Opus 5, Sonnet 5, Fable, Mythos): sending them returns a 400. Every
|
|
30
|
+
* Claude 4.x model accepts at most one of `temperature` / `top_p` (sending
|
|
31
|
+
* both is a 400). Claude 3.x and unrecognized IDs accept both.
|
|
32
|
+
*/
|
|
33
|
+
export declare function claudeSamplingSupport(modelId: string): SamplingSupport;
|
|
34
|
+
/** Anthropic's accepted `temperature` range; OpenAI's is 0..2. */
|
|
35
|
+
export declare const CLAUDE_TEMPERATURE_MAX = 1;
|
|
36
|
+
export type ClaudeEffort = "low" | "medium" | "high" | "xhigh" | "max";
|
|
37
|
+
/**
|
|
38
|
+
* Effort levels a generation accepts under `output_config.effort`; empty when
|
|
39
|
+
* effort is unsupported. `xhigh` arrived with Opus 4.7; `max` with 4.6; in
|
|
40
|
+
* the 4.5 generation only Opus 4.5 had an effort parameter at all (Sonnet
|
|
41
|
+
* 4.5 and Haiku 4.5 reject it).
|
|
42
|
+
*/
|
|
43
|
+
export declare function claudeEffortLadder(modelId: string): readonly ClaudeEffort[];
|
|
44
|
+
/**
|
|
45
|
+
* Last-assistant-turn prefill returns a 400 on Opus 4.6 / Sonnet 4.6 and every
|
|
46
|
+
* later model. Older generations still accept a trailing assistant message.
|
|
47
|
+
*/
|
|
48
|
+
export declare function claudeSupportsPrefill(modelId: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Native JSON-schema structured outputs (`output_config.format`) shipped with
|
|
51
|
+
* the 4.5 generation (Sonnet 4.5, Haiku 4.5, Opus 4.1) and every model since.
|
|
52
|
+
*/
|
|
53
|
+
export declare function claudeSupportsNativeJsonSchema(modelId: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Claude Fable 5.1 and Claude Mythos 5.1 return a 400 for forced tool use
|
|
56
|
+
* (`tool_choice` `any` / `tool`); everything else still honours it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function claudeSupportsForcedToolChoice(modelId: string): boolean;
|
|
59
|
+
//# sourceMappingURL=claude-generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-generation.d.ts","sourceRoot":"","sources":["../src/claude-generation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAgBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAUnF;AAMD,yDAAyD;AACzD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAMtE;AAED,kEAAkE;AAClE,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,YAAY,EAAE,CAO3E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI9D;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKvE;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKvE"}
|