summaryrefslogtreecommitdiffhomepage
path: root/packages/api/src
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-21 19:06:15 +0900
committerAdam Malczewski <[email protected]>2026-05-21 19:06:15 +0900
commit55633c90c0d96e62153a4b6655f3f833a3b46ad4 (patch)
treea75f97b48071eb1ba9e8366d8053a376dde69af5 /packages/api/src
parentd6b208342edf97bafa5b1dcc986b782f9879d141 (diff)
downloaddispatch-55633c90c0d96e62153a4b6655f3f833a3b46ad4.tar.gz
dispatch-55633c90c0d96e62153a4b6655f3f833a3b46ad4.zip
refactor: gut model/tag/fallback/agent-template system, fix Docker setup
- Remove ModelResolver, model definitions, model tags, fallback order, agent templates - Remove all [[models]], [agents], and fallback from dispatch.toml and config schema - ModelRegistry is now a pure key-state manager - dispatch.toml reduced to keys + permissions only - Docker: fix entrypoint for existing UID, skip bun install in frontend container - Docker: scoped build cache prune in bin/clean
Diffstat (limited to 'packages/api/src')
-rw-r--r--packages/api/src/agent-manager.ts59
-rw-r--r--packages/api/src/routes/models.ts44
2 files changed, 7 insertions, 96 deletions
diff --git a/packages/api/src/agent-manager.ts b/packages/api/src/agent-manager.ts
index 92396b6..6e78ad7 100644
--- a/packages/api/src/agent-manager.ts
+++ b/packages/api/src/agent-manager.ts
@@ -16,7 +16,6 @@ import {
loadSkills,
createSkillsWatcher,
ModelRegistry,
- ModelResolver,
TaskList,
createTaskListTool,
type ClaudeAccount,
@@ -53,7 +52,6 @@ export class AgentManager {
private config: DispatchConfig;
private skillsData: { skills: SkillDefinition[]; mappings: AgentSkillMapping[] };
private modelRegistry: ModelRegistry | null = null;
- private modelResolver: ModelResolver | null = null;
private taskList: TaskList;
private configWatcher: { close(): void } | null = null;
@@ -89,7 +87,6 @@ export class AgentManager {
setSkillsGetter(() => this.skillsData);
setModelsGetter(
() => this.modelRegistry,
- () => this.modelResolver,
);
setAccountsGetter(() => this.claudeAccounts);
@@ -135,17 +132,14 @@ export class AgentManager {
}
private _initModelRegistry(config: DispatchConfig): void {
- if (config.models && config.keys) {
+ if (config.keys) {
if (this.modelRegistry) {
- this.modelRegistry.updateConfig(config.models, config.keys, config.fallback ?? []);
+ this.modelRegistry.updateConfig(config.keys);
} else {
- this.modelRegistry = new ModelRegistry(config.models, config.keys, config.fallback ?? []);
- this.modelResolver = new ModelResolver(this.modelRegistry);
+ this.modelRegistry = new ModelRegistry(config.keys);
}
} else {
- // Models/keys removed from config — clear the registry
this.modelRegistry = null;
- this.modelResolver = null;
}
}
@@ -263,7 +257,7 @@ export class AgentManager {
}
}
} else {
- console.warn(`dispatch: key "${effectiveKeyId}" not found in model registry, falling back to tag-based resolution`);
+ console.warn(`dispatch: key "${effectiveKeyId}" not found in model registry`);
}
}
@@ -273,51 +267,6 @@ export class AgentManager {
this.activeModelId = null;
}
- if (!useOverride && this.modelRegistry && this.modelResolver) {
- // Try to get model_tag from default agent template, fall back to "heavy"
- const defaultAgent = this.config.agents?.["default"];
- const tag = defaultAgent?.model_tag ?? "heavy";
- const resolved = this.modelResolver.resolve(tag);
- if (resolved) {
- model = resolved.model.id;
- baseURL = resolved.key.base_url;
- // Check if resolved key is anthropic
- if (resolved.key.provider === "anthropic") {
- const credFile = resolved.key.credentials_file;
- const account = this.claudeAccounts.find((a) => a.id === resolved.key.id)
- ?? (credFile ? this.claudeAccounts.find((a) => a.source === credFile) : this.claudeAccounts[0]);
- if (account) {
- let creds = refreshAccountCredentials(account);
- if (!creds || creds.expiresAt <= Date.now() + 60_000) {
- creds = await refreshAccountCredentialsAsync(account);
- if (creds) account.credentials = creds;
- }
- if (creds) {
- claudeCredentials = { accessToken: creds.accessToken };
- apiKey = creds.accessToken;
- provider = "anthropic";
- } else {
- console.warn(`dispatch: no valid Claude credentials for key "${resolved.key.id}"`);
- }
- } else {
- console.warn(`dispatch: no Claude credentials found for key "${resolved.key.id}"`);
- }
- } else {
- const envKey = resolveApiKey(resolved.key.id);
- if (envKey) {
- apiKey = envKey;
- } else {
- console.warn(`dispatch: env var not set for key "${resolved.key.id}", falling back to defaults`);
- model = "deepseek-v4-flash";
- baseURL = "https://opencode.ai/zen/go/v1";
- apiKey = "";
- }
- }
- } else {
- console.warn(`dispatch: could not resolve model for tag "${tag}", falling back to env vars`);
- }
- }
-
this.agent = new Agent({
model,
apiKey,
diff --git a/packages/api/src/routes/models.ts b/packages/api/src/routes/models.ts
index ca58e38..86411f1 100644
--- a/packages/api/src/routes/models.ts
+++ b/packages/api/src/routes/models.ts
@@ -1,4 +1,4 @@
-import type { ModelRegistry, ModelResolver } from "@dispatch/core";
+import type { ModelRegistry } from "@dispatch/core";
import {
ANTHROPIC_MODELS_FALLBACK,
type ClaudeAccount,
@@ -20,15 +20,12 @@ import {
import { Hono } from "hono";
let getRegistry: () => ModelRegistry | null = () => null;
-let getResolver: () => ModelResolver | null = () => null;
let getAccounts: () => ClaudeAccount[] = () => [];
export function setModelsGetter(
registryGetter: () => ModelRegistry | null,
- resolverGetter: () => ModelResolver | null,
): void {
getRegistry = registryGetter;
- getResolver = resolverGetter;
}
export function setAccountsGetter(getter: () => ClaudeAccount[]): void {
@@ -45,11 +42,9 @@ export const modelsRoutes = new Hono();
modelsRoutes.get("/", (c) => {
const registry = getRegistry();
if (!registry) {
- return c.json({ models: [], tags: [], keys: [] });
+ return c.json({ keys: [] });
}
- const models = registry.getModels();
- const tags = registry.getAllTags();
const keyStates = registry.getKeys();
const keys = keyStates.map((ks) => ({
@@ -60,40 +55,7 @@ modelsRoutes.get("/", (c) => {
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,
- },
- },
- });
+ return c.json({ keys });
});
// Fetch available models for a specific provider key.