diff options
Diffstat (limited to 'packages/api/src/routes')
| -rw-r--r-- | packages/api/src/routes/config.ts | 27 | ||||
| -rw-r--r-- | packages/api/src/routes/models.ts | 69 | ||||
| -rw-r--r-- | packages/api/src/routes/skills.ts | 43 |
3 files changed, 139 insertions, 0 deletions
diff --git a/packages/api/src/routes/config.ts b/packages/api/src/routes/config.ts new file mode 100644 index 0000000..2d08167 --- /dev/null +++ b/packages/api/src/routes/config.ts @@ -0,0 +1,27 @@ +import { Hono } from "hono"; +import type { DispatchConfig } from "@dispatch/core"; + +let getConfig: () => DispatchConfig = () => ({ permissions: {} }); + +export function setConfigGetter(getter: () => DispatchConfig): void { + getConfig = getter; +} + +const configRoutes = new Hono(); + +configRoutes.get("/", (c) => { + const config = getConfig(); + + // Strip env field values from keys for security + const safeConfig: DispatchConfig = { + ...config, + keys: config.keys?.map((key) => ({ + ...key, + env: "***", + })), + }; + + return c.json({ config: safeConfig }); +}); + +export { configRoutes }; diff --git a/packages/api/src/routes/models.ts b/packages/api/src/routes/models.ts new file mode 100644 index 0000000..62f7340 --- /dev/null +++ b/packages/api/src/routes/models.ts @@ -0,0 +1,69 @@ +import { Hono } from "hono"; +import type { ModelRegistry, ModelResolver } from "@dispatch/core"; + +let getRegistry: () => ModelRegistry | null = () => null; +let getResolver: () => ModelResolver | null = () => null; + +export function setModelsGetter( + registryGetter: () => ModelRegistry | null, + resolverGetter: () => ModelResolver | null, +): void { + getRegistry = registryGetter; + getResolver = resolverGetter; +} + +export const modelsRoutes = new Hono(); + +modelsRoutes.get("/", (c) => { + const registry = getRegistry(); + if (!registry) { + return c.json({ models: [], tags: [], keys: [] }); + } + + const models = registry.getModels(); + const tags = registry.getAllTags(); + const keyStates = registry.getKeys(); + + const keys = keyStates.map((ks) => ({ + id: ks.definition.id, + provider: ks.definition.provider, + status: ks.status, + lastError: ks.lastError ?? null, + exhaustedAt: ks.exhaustedAt ?? null, + })); + + return c.json({ models, tags, keys }); +}); + +modelsRoutes.get("/resolve", (c) => { + const registry = getRegistry(); + const resolver = getResolver(); + if (!registry || !resolver) { + return c.json({ resolved: null, reason: "no models configured" }); + } + + const tag = c.req.query("tag"); + if (!tag) { + return c.json({ error: "tag query parameter is required" }, 400); + } + + const matchingModels = registry.getModelsByTag(tag); + if (matchingModels.length === 0) { + return c.json({ resolved: null, reason: "no models match tag" }); + } + + const resolved = resolver.resolve(tag); + if (!resolved) { + return c.json({ resolved: null, reason: "all keys exhausted for matching providers" }); + } + + return c.json({ + resolved: { + model: resolved.model, + key: { + id: resolved.key.id, + provider: resolved.key.provider, + }, + }, + }); +}); diff --git a/packages/api/src/routes/skills.ts b/packages/api/src/routes/skills.ts new file mode 100644 index 0000000..245fb4c --- /dev/null +++ b/packages/api/src/routes/skills.ts @@ -0,0 +1,43 @@ +import { Hono } from "hono"; +import type { AgentSkillMapping, SkillDefinition, SkillScope } from "@dispatch/core"; + +let getSkills: () => { skills: SkillDefinition[]; mappings: AgentSkillMapping[] } = () => ({ skills: [], mappings: [] }); + +export function setSkillsGetter(getter: () => { skills: SkillDefinition[]; mappings: AgentSkillMapping[] }): void { + getSkills = getter; +} + +export const skillsRoutes = new Hono(); + +skillsRoutes.get("/", (c) => { + const { skills, mappings } = getSkills(); + const skillSummaries = skills.map(({ name, description, tags, scope, directory }) => ({ + name, + description, + tags, + scope, + directory, + })); + return c.json({ skills: skillSummaries, mappings }); +}); + +skillsRoutes.get("/:name", (c) => { + const { name } = c.req.param(); + const scopeParam = c.req.query("scope") as SkillScope | undefined; + const { skills } = getSkills(); + + const matches = skills.filter((s) => s.name === name); + if (matches.length === 0) { + return c.json({ error: "Skill not found" }, 404); + } + + if (scopeParam) { + const scoped = matches.find((s) => s.scope === scopeParam); + if (!scoped) { + return c.json({ error: "Skill not found" }, 404); + } + return c.json(scoped); + } + + return c.json(matches[0]); +}); |
