@sriinnu/kosha-discovery 0.5.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 +286 -0
- package/dist/aliases.d.ts +51 -0
- package/dist/aliases.d.ts.map +1 -0
- package/dist/aliases.js +115 -0
- package/dist/aliases.js.map +1 -0
- package/dist/cache.d.ts +57 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +123 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli-commands.d.ts +142 -0
- package/dist/cli-commands.d.ts.map +1 -0
- package/dist/cli-commands.js +746 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/cli-format.d.ts +119 -0
- package/dist/cli-format.d.ts.map +1 -0
- package/dist/cli-format.js +171 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +143 -0
- package/dist/cli.js.map +1 -0
- package/dist/credentials/index.d.ts +2 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/resolver.d.ts +170 -0
- package/dist/credentials/resolver.d.ts.map +1 -0
- package/dist/credentials/resolver.js +597 -0
- package/dist/credentials/resolver.js.map +1 -0
- package/dist/discovery/anthropic.d.ts +49 -0
- package/dist/discovery/anthropic.d.ts.map +1 -0
- package/dist/discovery/anthropic.js +101 -0
- package/dist/discovery/anthropic.js.map +1 -0
- package/dist/discovery/base.d.ts +59 -0
- package/dist/discovery/base.d.ts.map +1 -0
- package/dist/discovery/base.js +123 -0
- package/dist/discovery/base.js.map +1 -0
- package/dist/discovery/bedrock.d.ts +122 -0
- package/dist/discovery/bedrock.d.ts.map +1 -0
- package/dist/discovery/bedrock.js +356 -0
- package/dist/discovery/bedrock.js.map +1 -0
- package/dist/discovery/cerebras.d.ts +43 -0
- package/dist/discovery/cerebras.d.ts.map +1 -0
- package/dist/discovery/cerebras.js +65 -0
- package/dist/discovery/cerebras.js.map +1 -0
- package/dist/discovery/cohere.d.ts +57 -0
- package/dist/discovery/cohere.d.ts.map +1 -0
- package/dist/discovery/cohere.js +82 -0
- package/dist/discovery/cohere.js.map +1 -0
- package/dist/discovery/deepinfra.d.ts +41 -0
- package/dist/discovery/deepinfra.d.ts.map +1 -0
- package/dist/discovery/deepinfra.js +86 -0
- package/dist/discovery/deepinfra.js.map +1 -0
- package/dist/discovery/deepseek.d.ts +17 -0
- package/dist/discovery/deepseek.d.ts.map +1 -0
- package/dist/discovery/deepseek.js +45 -0
- package/dist/discovery/deepseek.js.map +1 -0
- package/dist/discovery/fireworks.d.ts +48 -0
- package/dist/discovery/fireworks.d.ts.map +1 -0
- package/dist/discovery/fireworks.js +101 -0
- package/dist/discovery/fireworks.js.map +1 -0
- package/dist/discovery/glm.d.ts +17 -0
- package/dist/discovery/glm.d.ts.map +1 -0
- package/dist/discovery/glm.js +52 -0
- package/dist/discovery/glm.js.map +1 -0
- package/dist/discovery/google.d.ts +53 -0
- package/dist/discovery/google.d.ts.map +1 -0
- package/dist/discovery/google.js +122 -0
- package/dist/discovery/google.js.map +1 -0
- package/dist/discovery/groq.d.ts +44 -0
- package/dist/discovery/groq.d.ts.map +1 -0
- package/dist/discovery/groq.js +89 -0
- package/dist/discovery/groq.js.map +1 -0
- package/dist/discovery/index.d.ts +48 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +116 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/llama-cpp.d.ts +45 -0
- package/dist/discovery/llama-cpp.d.ts.map +1 -0
- package/dist/discovery/llama-cpp.js +137 -0
- package/dist/discovery/llama-cpp.js.map +1 -0
- package/dist/discovery/minimax.d.ts +16 -0
- package/dist/discovery/minimax.d.ts.map +1 -0
- package/dist/discovery/minimax.js +56 -0
- package/dist/discovery/minimax.js.map +1 -0
- package/dist/discovery/mistral.d.ts +45 -0
- package/dist/discovery/mistral.d.ts.map +1 -0
- package/dist/discovery/mistral.js +82 -0
- package/dist/discovery/mistral.js.map +1 -0
- package/dist/discovery/moonshot.d.ts +16 -0
- package/dist/discovery/moonshot.d.ts.map +1 -0
- package/dist/discovery/moonshot.js +46 -0
- package/dist/discovery/moonshot.js.map +1 -0
- package/dist/discovery/nvidia.d.ts +60 -0
- package/dist/discovery/nvidia.d.ts.map +1 -0
- package/dist/discovery/nvidia.js +145 -0
- package/dist/discovery/nvidia.js.map +1 -0
- package/dist/discovery/ollama.d.ts +57 -0
- package/dist/discovery/ollama.d.ts.map +1 -0
- package/dist/discovery/ollama.js +151 -0
- package/dist/discovery/ollama.js.map +1 -0
- package/dist/discovery/openai-compatible.d.ts +126 -0
- package/dist/discovery/openai-compatible.d.ts.map +1 -0
- package/dist/discovery/openai-compatible.js +161 -0
- package/dist/discovery/openai-compatible.js.map +1 -0
- package/dist/discovery/openai.d.ts +62 -0
- package/dist/discovery/openai.d.ts.map +1 -0
- package/dist/discovery/openai.js +157 -0
- package/dist/discovery/openai.js.map +1 -0
- package/dist/discovery/openrouter.d.ts +78 -0
- package/dist/discovery/openrouter.d.ts.map +1 -0
- package/dist/discovery/openrouter.js +184 -0
- package/dist/discovery/openrouter.js.map +1 -0
- package/dist/discovery/perplexity.d.ts +66 -0
- package/dist/discovery/perplexity.d.ts.map +1 -0
- package/dist/discovery/perplexity.js +86 -0
- package/dist/discovery/perplexity.js.map +1 -0
- package/dist/discovery/together.d.ts +41 -0
- package/dist/discovery/together.d.ts.map +1 -0
- package/dist/discovery/together.js +88 -0
- package/dist/discovery/together.js.map +1 -0
- package/dist/discovery/vertex.d.ts +146 -0
- package/dist/discovery/vertex.d.ts.map +1 -0
- package/dist/discovery/vertex.js +371 -0
- package/dist/discovery/vertex.js.map +1 -0
- package/dist/discovery/zai.d.ts +17 -0
- package/dist/discovery/zai.d.ts.map +1 -0
- package/dist/discovery/zai.js +51 -0
- package/dist/discovery/zai.js.map +1 -0
- package/dist/discovery-contract.d.ts +186 -0
- package/dist/discovery-contract.d.ts.map +1 -0
- package/dist/discovery-contract.js +115 -0
- package/dist/discovery-contract.js.map +1 -0
- package/dist/discovery-routes.d.ts +14 -0
- package/dist/discovery-routes.d.ts.map +1 -0
- package/dist/discovery-routes.js +98 -0
- package/dist/discovery-routes.js.map +1 -0
- package/dist/enrichment/index.d.ts +2 -0
- package/dist/enrichment/index.d.ts.map +1 -0
- package/dist/enrichment/index.js +2 -0
- package/dist/enrichment/index.js.map +1 -0
- package/dist/enrichment/litellm.d.ts +52 -0
- package/dist/enrichment/litellm.d.ts.map +1 -0
- package/dist/enrichment/litellm.js +205 -0
- package/dist/enrichment/litellm.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +64 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +166 -0
- package/dist/normalize.js.map +1 -0
- package/dist/provider-catalog.d.ts +62 -0
- package/dist/provider-catalog.d.ts.map +1 -0
- package/dist/provider-catalog.js +331 -0
- package/dist/provider-catalog.js.map +1 -0
- package/dist/registry-delta.d.ts +17 -0
- package/dist/registry-delta.d.ts.map +1 -0
- package/dist/registry-delta.js +74 -0
- package/dist/registry-delta.js.map +1 -0
- package/dist/registry-discovery.d.ts +66 -0
- package/dist/registry-discovery.d.ts.map +1 -0
- package/dist/registry-discovery.js +339 -0
- package/dist/registry-discovery.js.map +1 -0
- package/dist/registry-query.d.ts +74 -0
- package/dist/registry-query.d.ts.map +1 -0
- package/dist/registry-query.js +310 -0
- package/dist/registry-query.js.map +1 -0
- package/dist/registry-runtime.d.ts +48 -0
- package/dist/registry-runtime.d.ts.map +1 -0
- package/dist/registry-runtime.js +255 -0
- package/dist/registry-runtime.js.map +1 -0
- package/dist/registry-selection.d.ts +31 -0
- package/dist/registry-selection.d.ts.map +1 -0
- package/dist/registry-selection.js +167 -0
- package/dist/registry-selection.js.map +1 -0
- package/dist/registry-state.d.ts +92 -0
- package/dist/registry-state.d.ts.map +1 -0
- package/dist/registry-state.js +35 -0
- package/dist/registry-state.js.map +1 -0
- package/dist/registry.d.ts +127 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +248 -0
- package/dist/registry.js.map +1 -0
- package/dist/resilience.d.ts +212 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +292 -0
- package/dist/resilience.js.map +1 -0
- package/dist/security.d.ts +44 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +184 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +41 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +320 -0
- package/dist/server.js.map +1 -0
- package/dist/shell-safe.d.ts +15 -0
- package/dist/shell-safe.d.ts.map +1 -0
- package/dist/shell-safe.js +20 -0
- package/dist/shell-safe.js.map +1 -0
- package/dist/types.d.ts +365 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/logo.svg +81 -0
- package/package.json +85 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — HTTP API server (Hono-based).
|
|
3
|
+
*
|
|
4
|
+
* Exposes the model registry over a lightweight REST API so that
|
|
5
|
+
* editor extensions, scripts, and other tools can query discovered
|
|
6
|
+
* models without importing the library directly.
|
|
7
|
+
*
|
|
8
|
+
* Routes:
|
|
9
|
+
* GET /api/models — List models (query: ?provider, ?originProvider, ?mode, ?capability)
|
|
10
|
+
* GET /api/models/cheapest — Cheapest eligible models for a role/capability
|
|
11
|
+
* GET /api/models/:idOrAlias/routes — All provider routes with preferred/direct metadata
|
|
12
|
+
* GET /api/models/:idOrAlias — Get a single model by ID or alias (+ baseUrl/version)
|
|
13
|
+
* GET /api/roles — Provider->model->roles matrix
|
|
14
|
+
* GET /api/providers — List all providers (summary)
|
|
15
|
+
* GET /api/providers/:id — Get a single provider with its models
|
|
16
|
+
* POST /api/refresh — Trigger re-discovery (body: { provider?: string })
|
|
17
|
+
* GET /api/resolve/:alias — Resolve an alias to its canonical model ID
|
|
18
|
+
* GET /api/discovery-errors — Errors from last discovery pass
|
|
19
|
+
* GET /health — Health check
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { Hono } from "hono";
|
|
23
|
+
import { serve } from "@hono/node-server";
|
|
24
|
+
import { registerDiscoveryRoutes } from "./discovery-routes.js";
|
|
25
|
+
import { ModelRegistry } from "./registry.js";
|
|
26
|
+
import { extractModelVersion, normalizeModelId } from "./normalize.js";
|
|
27
|
+
const MODEL_MODES = ["chat", "embedding", "image", "audio", "moderation", "rerank"];
|
|
28
|
+
const PRICE_METRICS = ["input", "output", "blended"];
|
|
29
|
+
function parseMode(value) {
|
|
30
|
+
if (!value)
|
|
31
|
+
return undefined;
|
|
32
|
+
if (MODEL_MODES.includes(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
function parseNumber(value) {
|
|
38
|
+
if (!value)
|
|
39
|
+
return undefined;
|
|
40
|
+
const n = Number(value);
|
|
41
|
+
if (!Number.isFinite(n))
|
|
42
|
+
return undefined;
|
|
43
|
+
return n;
|
|
44
|
+
}
|
|
45
|
+
function parsePriceMetric(value) {
|
|
46
|
+
if (!value)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (PRICE_METRICS.includes(value)) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Server factory
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
/**
|
|
57
|
+
* Create a Hono application wired to the given {@link ModelRegistry}.
|
|
58
|
+
*
|
|
59
|
+
* The returned app is not yet listening — call `serve()` or mount it
|
|
60
|
+
* inside another Hono app to start accepting requests.
|
|
61
|
+
*
|
|
62
|
+
* @param registry - A pre-populated (or lazy) ModelRegistry instance.
|
|
63
|
+
* @returns A configured Hono app with all kosha REST routes.
|
|
64
|
+
*/
|
|
65
|
+
export function createServer(registry) {
|
|
66
|
+
const app = new Hono();
|
|
67
|
+
registerDiscoveryRoutes(app, registry);
|
|
68
|
+
// ── Model listing & lookup routes ────────────────────────────────
|
|
69
|
+
//
|
|
70
|
+
// GET /api/models supports four optional query parameters:
|
|
71
|
+
// ?provider=anthropic — filter by serving-layer provider slug
|
|
72
|
+
// ?originProvider=anthropic — filter by original model creator
|
|
73
|
+
// ?mode=chat — filter by ModelMode
|
|
74
|
+
// ?capability=vision — filter by capability flag
|
|
75
|
+
app.get("/api/models", (ctx) => {
|
|
76
|
+
const provider = ctx.req.query("provider") ?? undefined;
|
|
77
|
+
const originProvider = ctx.req.query("originProvider") ?? undefined;
|
|
78
|
+
const mode = parseMode(ctx.req.query("mode"));
|
|
79
|
+
const capability = ctx.req.query("capability") ?? undefined;
|
|
80
|
+
const models = registry.models({ provider, originProvider, mode, capability });
|
|
81
|
+
return ctx.json({
|
|
82
|
+
models,
|
|
83
|
+
count: models.length,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
// Ranked cheapest model lookup for routing decisions. Route must be
|
|
87
|
+
// registered before dynamic /api/models/:idOrAlias.
|
|
88
|
+
app.get("/api/models/cheapest", (ctx) => {
|
|
89
|
+
const options = {
|
|
90
|
+
role: ctx.req.query("role") ?? undefined,
|
|
91
|
+
capability: ctx.req.query("capability") ?? undefined,
|
|
92
|
+
provider: ctx.req.query("provider") ?? undefined,
|
|
93
|
+
originProvider: ctx.req.query("originProvider") ?? undefined,
|
|
94
|
+
mode: parseMode(ctx.req.query("mode")),
|
|
95
|
+
limit: parseNumber(ctx.req.query("limit")),
|
|
96
|
+
priceMetric: parsePriceMetric(ctx.req.query("priceMetric")),
|
|
97
|
+
inputWeight: parseNumber(ctx.req.query("inputWeight")),
|
|
98
|
+
outputWeight: parseNumber(ctx.req.query("outputWeight")),
|
|
99
|
+
includeUnpriced: ctx.req.query("includeUnpriced") === "true",
|
|
100
|
+
};
|
|
101
|
+
const result = registry.cheapestModels(options);
|
|
102
|
+
const message = result.matches.length > 0
|
|
103
|
+
? undefined
|
|
104
|
+
: result.missingCredentials.length > 0
|
|
105
|
+
? "No priced models found. Add credentials for one of the missing providers."
|
|
106
|
+
: "No priced models found for the requested filters.";
|
|
107
|
+
return ctx.json({
|
|
108
|
+
...result,
|
|
109
|
+
cheapest: result.matches[0] ?? null,
|
|
110
|
+
message,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
// Provider/model role matrix for assistant planners and model routers.
|
|
114
|
+
app.get("/api/roles", (ctx) => {
|
|
115
|
+
const options = {
|
|
116
|
+
role: ctx.req.query("role") ?? undefined,
|
|
117
|
+
capability: ctx.req.query("capability") ?? undefined,
|
|
118
|
+
provider: ctx.req.query("provider") ?? undefined,
|
|
119
|
+
originProvider: ctx.req.query("originProvider") ?? undefined,
|
|
120
|
+
mode: parseMode(ctx.req.query("mode")),
|
|
121
|
+
};
|
|
122
|
+
const providers = registry.providerRoles(options);
|
|
123
|
+
const providerIds = options.provider
|
|
124
|
+
? [options.provider]
|
|
125
|
+
: registry.providers_list().map((provider) => provider.id);
|
|
126
|
+
const modelCount = providers.reduce((sum, provider) => sum + provider.models.length, 0);
|
|
127
|
+
return ctx.json({
|
|
128
|
+
providers,
|
|
129
|
+
count: providers.length,
|
|
130
|
+
modelCount,
|
|
131
|
+
missingCredentials: registry.missingCredentialPrompts(providerIds),
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
// ── Capability aggregation route ─────────────────────────────────
|
|
135
|
+
//
|
|
136
|
+
// Returns a summary of all capabilities across the ecosystem.
|
|
137
|
+
// Optional ?provider= filter to scope to one provider.
|
|
138
|
+
app.get("/api/capabilities", (ctx) => {
|
|
139
|
+
const provider = ctx.req.query("provider") ?? undefined;
|
|
140
|
+
const caps = registry.capabilities({ provider });
|
|
141
|
+
const providerIds = provider
|
|
142
|
+
? [provider]
|
|
143
|
+
: registry.providers_list().map((p) => p.id);
|
|
144
|
+
return ctx.json({
|
|
145
|
+
capabilities: caps,
|
|
146
|
+
count: caps.length,
|
|
147
|
+
missingCredentials: registry.missingCredentialPrompts(providerIds),
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
// All provider routes for a single model — must be registered BEFORE the
|
|
151
|
+
// generic /:idOrAlias route so that Hono matches "/routes" as a literal
|
|
152
|
+
// segment rather than treating it as a dynamic parameter value.
|
|
153
|
+
//
|
|
154
|
+
// Returns the normalized base ID plus every serving-layer ModelCard that
|
|
155
|
+
// resolves to the same underlying model (direct, openrouter, bedrock, etc.).
|
|
156
|
+
app.get("/api/models/:idOrAlias/routes", (ctx) => {
|
|
157
|
+
const idOrAlias = ctx.req.param("idOrAlias");
|
|
158
|
+
const routes = registry.modelRouteInfo(idOrAlias);
|
|
159
|
+
if (routes.length === 0) {
|
|
160
|
+
return ctx.json({ error: "Model not found", id: idOrAlias }, 404);
|
|
161
|
+
}
|
|
162
|
+
return ctx.json({
|
|
163
|
+
model: normalizeModelId(idOrAlias),
|
|
164
|
+
preferredProvider: routes.find((route) => route.isPreferred)?.provider,
|
|
165
|
+
routes,
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
// Single model lookup — accepts a canonical ID or a short alias
|
|
169
|
+
app.get("/api/models/:idOrAlias", (ctx) => {
|
|
170
|
+
const idOrAlias = ctx.req.param("idOrAlias");
|
|
171
|
+
const model = registry.model(idOrAlias);
|
|
172
|
+
if (!model) {
|
|
173
|
+
return ctx.json({ error: "Model not found", id: idOrAlias }, 404);
|
|
174
|
+
}
|
|
175
|
+
const provider = registry.provider(model.provider);
|
|
176
|
+
return ctx.json({
|
|
177
|
+
...model,
|
|
178
|
+
baseUrl: provider?.baseUrl,
|
|
179
|
+
version: extractModelVersion(model.id),
|
|
180
|
+
resolvedOriginProvider: model.originProvider ?? model.provider,
|
|
181
|
+
isDirectProvider: !model.originProvider || model.originProvider === model.provider,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
// ── Provider listing & lookup routes ─────────────────────────────
|
|
185
|
+
//
|
|
186
|
+
// The list endpoint returns a lightweight summary (no full model arrays)
|
|
187
|
+
// to keep payloads small; use /api/providers/:id for the full detail.
|
|
188
|
+
app.get("/api/providers", (ctx) => {
|
|
189
|
+
const prompts = registry.missingCredentialPrompts();
|
|
190
|
+
const promptByProvider = new Map(prompts.map((prompt) => [prompt.providerId, prompt]));
|
|
191
|
+
const providers = registry.providers_list().map((p) => {
|
|
192
|
+
const prompt = promptByProvider.get(p.id);
|
|
193
|
+
return {
|
|
194
|
+
id: p.id,
|
|
195
|
+
name: p.name,
|
|
196
|
+
baseUrl: p.baseUrl,
|
|
197
|
+
authenticated: p.authenticated,
|
|
198
|
+
credentialSource: p.credentialSource,
|
|
199
|
+
modelCount: p.models.length,
|
|
200
|
+
lastRefreshed: p.lastRefreshed,
|
|
201
|
+
missingCredentialPrompt: prompt?.message,
|
|
202
|
+
credentialEnvVars: prompt?.envVars ?? [],
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
return ctx.json({
|
|
206
|
+
providers,
|
|
207
|
+
count: providers.length,
|
|
208
|
+
missingCredentials: prompts,
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
// Full provider detail including all of its models
|
|
212
|
+
app.get("/api/providers/:id", (ctx) => {
|
|
213
|
+
const id = ctx.req.param("id");
|
|
214
|
+
const provider = registry.provider(id);
|
|
215
|
+
if (!provider) {
|
|
216
|
+
return ctx.json({ error: "Provider not found", id }, 404);
|
|
217
|
+
}
|
|
218
|
+
const prompt = registry.missingCredentialPrompts([provider.id])[0];
|
|
219
|
+
return ctx.json({
|
|
220
|
+
...provider,
|
|
221
|
+
missingCredentialPrompt: prompt?.message,
|
|
222
|
+
credentialEnvVars: prompt?.envVars ?? [],
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
// ── Mutation routes ──────────────────────────────────────────────
|
|
226
|
+
//
|
|
227
|
+
// POST /api/refresh triggers a fresh discovery pass. Optionally
|
|
228
|
+
// accepts { provider: "anthropic" } to refresh only one provider.
|
|
229
|
+
app.post("/api/refresh", async (ctx) => {
|
|
230
|
+
const body = await ctx.req.json().catch(() => ({}));
|
|
231
|
+
const providerId = body.provider;
|
|
232
|
+
try {
|
|
233
|
+
await registry.refresh(providerId);
|
|
234
|
+
const providers = registry.providers_list();
|
|
235
|
+
const totalModels = providers.reduce((sum, p) => sum + p.models.length, 0);
|
|
236
|
+
return ctx.json({
|
|
237
|
+
status: "ok",
|
|
238
|
+
providers: providers.length,
|
|
239
|
+
models: totalModels,
|
|
240
|
+
refreshedAt: Date.now(),
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
245
|
+
return ctx.json({ error: "Refresh failed", message }, 500);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
// ── Alias resolution route ───────────────────────────────────────
|
|
249
|
+
app.get("/api/resolve/:alias", (ctx) => {
|
|
250
|
+
const alias = ctx.req.param("alias");
|
|
251
|
+
const resolved = registry.resolve(alias);
|
|
252
|
+
return ctx.json({
|
|
253
|
+
alias,
|
|
254
|
+
resolved,
|
|
255
|
+
isAlias: resolved !== alias,
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
// ── Discovery error reporting ────────────────────────────────────
|
|
259
|
+
//
|
|
260
|
+
// Returns errors from the most recent discovery pass so operators
|
|
261
|
+
// can diagnose which providers failed and why.
|
|
262
|
+
app.get("/api/discovery-errors", (ctx) => {
|
|
263
|
+
const errors = registry.discoveryErrors();
|
|
264
|
+
return ctx.json({
|
|
265
|
+
errors,
|
|
266
|
+
count: errors.length,
|
|
267
|
+
hasErrors: errors.length > 0,
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
// ── Health check ─────────────────────────────────────────────────
|
|
271
|
+
app.get("/health", (ctx) => {
|
|
272
|
+
const providers = registry.providers_list();
|
|
273
|
+
return ctx.json({
|
|
274
|
+
status: "ok",
|
|
275
|
+
models: registry.models().length,
|
|
276
|
+
providers: providers.length,
|
|
277
|
+
uptime: process.uptime(),
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
return app;
|
|
281
|
+
}
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
// Standalone server entry point
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
/**
|
|
286
|
+
* Boot a standalone kosha API server.
|
|
287
|
+
*
|
|
288
|
+
* Runs full discovery, then starts an HTTP listener on the given port.
|
|
289
|
+
* @param port - TCP port to bind (default `3000`, overridable via `PORT` env var).
|
|
290
|
+
*/
|
|
291
|
+
export async function startServer(port = 3000) {
|
|
292
|
+
const registry = new ModelRegistry();
|
|
293
|
+
console.log("Discovering providers and models...");
|
|
294
|
+
await registry.discover();
|
|
295
|
+
const providers = registry.providers_list();
|
|
296
|
+
const totalModels = registry.models().length;
|
|
297
|
+
console.log(`Found ${totalModels} models from ${providers.length} providers`);
|
|
298
|
+
const app = createServer(registry);
|
|
299
|
+
console.log(`\nKosha API server listening on http://localhost:${port}`);
|
|
300
|
+
console.log(` GET http://localhost:${port}/api/models`);
|
|
301
|
+
console.log(` GET http://localhost:${port}/api/models/cheapest`);
|
|
302
|
+
console.log(` GET http://localhost:${port}/api/models/:id/routes`);
|
|
303
|
+
console.log(` GET http://localhost:${port}/api/capabilities`);
|
|
304
|
+
console.log(` GET http://localhost:${port}/api/roles`);
|
|
305
|
+
console.log(` GET http://localhost:${port}/api/providers`);
|
|
306
|
+
console.log(` GET http://localhost:${port}/api/discovery`);
|
|
307
|
+
console.log(` GET http://localhost:${port}/api/discovery/delta`);
|
|
308
|
+
console.log(` GET http://localhost:${port}/api/discovery/watch`);
|
|
309
|
+
console.log(` GET http://localhost:${port}/health`);
|
|
310
|
+
serve({ fetch: app.fetch, port });
|
|
311
|
+
}
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
// Auto-start when executed directly (e.g. `node dist/server.js`)
|
|
314
|
+
// ---------------------------------------------------------------------------
|
|
315
|
+
const isEntryPoint = import.meta.url === `file://${process.argv[1]}`;
|
|
316
|
+
if (isEntryPoint) {
|
|
317
|
+
const port = parseInt(process.env.PORT || "3000", 10);
|
|
318
|
+
startServer(port);
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell safety utilities — input validation for values passed to CLI subprocesses.
|
|
3
|
+
*
|
|
4
|
+
* Prevents command injection by rejecting values that contain shell
|
|
5
|
+
* metacharacters. Only alphanumeric characters, hyphens, underscores,
|
|
6
|
+
* and dots are allowed.
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Validate that a string is safe to pass as a CLI argument.
|
|
11
|
+
*
|
|
12
|
+
* @throws {Error} When the value contains characters outside the safe set.
|
|
13
|
+
*/
|
|
14
|
+
export declare function assertSafeShellArg(value: string, label: string): void;
|
|
15
|
+
//# sourceMappingURL=shell-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-safe.d.ts","sourceRoot":"","sources":["../src/shell-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMrE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell safety utilities — input validation for values passed to CLI subprocesses.
|
|
3
|
+
*
|
|
4
|
+
* Prevents command injection by rejecting values that contain shell
|
|
5
|
+
* metacharacters. Only alphanumeric characters, hyphens, underscores,
|
|
6
|
+
* and dots are allowed.
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
const SAFE_CLI_ARG = /^[a-zA-Z0-9._-]+$/;
|
|
10
|
+
/**
|
|
11
|
+
* Validate that a string is safe to pass as a CLI argument.
|
|
12
|
+
*
|
|
13
|
+
* @throws {Error} When the value contains characters outside the safe set.
|
|
14
|
+
*/
|
|
15
|
+
export function assertSafeShellArg(value, label) {
|
|
16
|
+
if (!SAFE_CLI_ARG.test(value)) {
|
|
17
|
+
throw new Error(`Unsafe ${label} value: "${value}" — only alphanumeric characters, hyphens, underscores, and dots are allowed`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=shell-safe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-safe.js","sourceRoot":"","sources":["../src/shell-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,KAAa;IAC9D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACd,UAAU,KAAK,YAAY,KAAK,8EAA8E,CAC9G,CAAC;IACH,CAAC;AACF,CAAC"}
|