From 91868577fa2bad1b3e72d08c1dac0f3792289c91 Mon Sep 17 00:00:00 2001 From: 9qeklajc <9qeklajc> Date: Wed, 1 Jul 2026 17:18:08 +0200 Subject: [PATCH] provider updates through slug --- src/commands/instruct.ts | 26 ++++++++++---------- src/commands/provider-models.ts | 8 ++++--- src/commands/providers.ts | 13 +++++++--- src/index.ts | 42 +++++++++++++++++++-------------- src/types.ts | 1 + 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/commands/instruct.ts b/src/commands/instruct.ts index eef76c3..9f94f85 100644 --- a/src/commands/instruct.ts +++ b/src/commands/instruct.ts @@ -93,24 +93,26 @@ Global flags (apply to every command): - \`routstr models list [--provider ]\` — pricing for all enabled models ### Providers (admin-only) -- \`routstr providers list -t \` — upstream providers -- \`routstr providers show -t \` — full provider details -- \`routstr providers add --base-url --api-key -t \` -- \`routstr providers update [--type|--base-url|--api-key|--api-version|--enabled |--fee |--settings ] -t \` -- \`routstr providers enable -t \` / \`disable \` -- \`routstr providers remove -t \` -- \`routstr providers test -t \` — health-check upstream +Provider refs accept either numeric ID or stable slug. Prefer slugs in automation. +- \`routstr providers list -t \` — upstream providers, including stable \`slug\` +- \`routstr providers show -t \` — full provider details by ID or slug +- \`routstr providers add --base-url --api-key [--slug ] -t \` +- \`routstr providers update [--type|--base-url|--api-key|--api-version|--enabled |--fee |--settings |--slug ] -t \` +- \`routstr providers enable -t \` / \`disable \` +- \`routstr providers remove -t \` +- \`routstr providers test -t \` — health-check upstream ### Provider models (per-model edits scoped to a provider; admin-only) -- \`routstr providers models list [--source all|db|remote] -t \` — DB + upstream-discovered models -- \`routstr providers models show -t \` — full model detail -- \`routstr providers models update [--forwarded-model-id |--enabled |--name|--description] -t \` +Use the provider slug from \`routstr providers list -t -o json\` as \`\` when possible. +- \`routstr providers models list [--source all|db|remote] -t \` — DB + upstream-discovered models +- \`routstr providers models show -t \` — full model detail +- \`routstr providers models update [--forwarded-model-id |--enabled |--name|--description] -t \` Batch update example (loop over ids): \`\`\` -routstr providers models list --source db -o json -t \\ +routstr providers models list --source db -o json -t \\ | jq -r '.db_models[].id' \\ - | xargs -I{} routstr providers models update {} --forwarded-model-id {} -t + | xargs -I{} routstr providers models update {} --forwarded-model-id {} -t \`\`\` ### Wallet diff --git a/src/commands/provider-models.ts b/src/commands/provider-models.ts index 2db31bb..508b001 100644 --- a/src/commands/provider-models.ts +++ b/src/commands/provider-models.ts @@ -36,7 +36,7 @@ function parseBool(value: string): boolean { } interface ProviderModelsResponse { - provider: { id: number; provider_type: string; base_url: string }; + provider: { id: number; slug?: string | null; provider_type: string; base_url: string }; db_models: AdminModel[]; remote_models: AdminModel[]; } @@ -79,13 +79,15 @@ export async function providerModelsListCommand( rows.push([m.id, "remote", "—", "—", m.name ?? ""]); } + const providerLabel = d.provider.slug ?? `#${d.provider.id}`; + if (!rows.length) { - printInfo(`No models for provider #${d.provider.id} (source=${source}).`); + printInfo(`No models for provider ${providerLabel} (source=${source}).`); return; } printTable( - `Models for provider #${d.provider.id} — ${d.provider.provider_type} (${rows.length})`, + `Models for provider ${providerLabel} — ${d.provider.provider_type} (${rows.length})`, ["ID", "Source", "Enabled", "Forwarded ID", "Name"], rows, ); diff --git a/src/commands/providers.ts b/src/commands/providers.ts index 6b56b4f..4250ade 100644 --- a/src/commands/providers.ts +++ b/src/commands/providers.ts @@ -19,6 +19,7 @@ export async function providersListCommand(opts: { adminToken?: string }): Promi const resp = await fetchJson< Array<{ id: number; + slug?: string | null; provider_type: string; base_url: string; enabled: boolean; @@ -34,6 +35,7 @@ export async function providersListCommand(opts: { adminToken?: string }): Promi } const rows = items.map((p) => [ String(p.id), + p.slug ?? "—", p.provider_type, p.base_url, p.enabled ? "yes" : "no", @@ -41,7 +43,7 @@ export async function providersListCommand(opts: { adminToken?: string }): Promi ]); printTable( `Upstream Providers (${items.length})`, - ["ID", "Type", "URL", "Enabled", "Fee"], + ["ID", "Slug", "Type", "URL", "Enabled", "Fee"], rows, ); }); @@ -77,7 +79,7 @@ export async function providersListCommand(opts: { adminToken?: string }): Promi export async function providersAddCommand( name: string, - opts: { apiKey?: string; baseUrl?: string; adminToken?: string }, + opts: { apiKey?: string; baseUrl?: string; adminToken?: string; slug?: string }, ): Promise { const token = resolveToken(opts.adminToken); const url = `${nodeUrl()}/admin/api/upstream-providers`; @@ -86,6 +88,7 @@ export async function providersAddCommand( base_url: opts.baseUrl ?? "", api_key: opts.apiKey ?? "", }; + if (opts.slug !== undefined) body.slug = opts.slug; const headers: Record = { "Content-Type": "application/json", @@ -162,6 +165,7 @@ export async function providersTestCommand( interface UpstreamProviderDetail { id: number; + slug?: string | null; provider_type: string; base_url: string; api_key: string; @@ -186,6 +190,7 @@ export async function providersShowCommand( render(data, (p) => { printInfo(`\x1b[1mProvider #${p.id}\x1b[0m`); + if (p.slug) printInfo(` Slug: ${p.slug}`); printInfo(` Type: ${p.provider_type}`); printInfo(` Base URL: ${p.base_url}`); printInfo(` API key: ${p.api_key || "(none)"}`); @@ -207,6 +212,7 @@ interface UpdateProviderOptions { enabled?: string; fee?: string; settings?: string; + slug?: string; } function parseBool(value: string): boolean { @@ -251,10 +257,11 @@ export async function providersUpdateCommand( process.exit(1); } } + if (opts.slug !== undefined) body.slug = opts.slug; if (Object.keys(body).length === 0) { printError( - "No fields to update. Pass one of: --type, --base-url, --api-key, --api-version, --enabled, --fee, --settings.", + "No fields to update. Pass one of: --type, --base-url, --api-key, --api-version, --enabled, --fee, --settings, --slug.", ); process.exit(1); } diff --git a/src/index.ts b/src/index.ts index 2a0cf6b..f5031b3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -101,26 +101,27 @@ providersCmd .description("Add a new upstream provider (requires admin token)") .option("--api-key ", "Provider API key") .option("--base-url ", "Provider base URL") + .option("--slug ", "Stable provider slug (auto-generated if omitted)") .option("-t, --admin-token ", "Admin session token") .action(providersAddCommand); providersCmd - .command("remove ") - .description("Remove an upstream provider by ID (requires admin token)") + .command("remove ") + .description("Remove an upstream provider by ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .action(providersRemoveCommand); providersCmd - .command("test ") - .description("Health check a provider by ID (requires admin token)") + .command("test ") + .description("Health check a provider by ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .action(providersTestCommand); providersCmd - .command("show ") - .description("Show full details for a provider (requires admin token)") + .command("show ") + .description("Show full details for a provider by ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .action(providersShowCommand); providersCmd - .command("update ") - .description("Update provider fields (requires admin token)") + .command("update ") + .description("Update provider fields by ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .option("--type ", "Provider type (openai, anthropic, azure, openrouter, custom, ...)") .option("--base-url ", "Upstream base URL") @@ -129,15 +130,16 @@ providersCmd .option("--enabled ", "Enable/disable provider (true|false)") .option("--fee ", "Provider fee multiplier (e.g. 1.01 for 1%)") .option("--settings ", "Provider-specific settings as JSON") + .option("--slug ", "Set/rename the stable provider slug") .action(providersUpdateCommand); providersCmd - .command("enable ") - .description("Enable a provider (requires admin token)") + .command("enable ") + .description("Enable a provider by ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .action(providersEnableCommand); providersCmd - .command("disable ") - .description("Disable a provider (requires admin token)") + .command("disable ") + .description("Disable a provider by ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .action(providersDisableCommand); @@ -146,19 +148,23 @@ const providerModelsCmd = providersCmd .command("models") .description("Manage models attached to a provider"); providerModelsCmd - .command("list ") - .description("List models for a provider — DB + remote upstream models (requires admin token)") + .command("list ") + .description( + "List models for a provider ID or slug — DB + remote upstream models (requires admin token)", + ) .option("-t, --admin-token ", "Admin session token") .option("--source ", "Filter: all | db | remote", "all") .action(providerModelsListCommand); providerModelsCmd - .command("show ") - .description("Show full details for a model (requires admin token)") + .command("show ") + .description("Show full details for a model by provider ID or slug (requires admin token)") .option("-t, --admin-token ", "Admin session token") .action(providerModelsShowCommand); providerModelsCmd - .command("update ") - .description("Update a single model's mutable fields (requires admin token)") + .command("update ") + .description( + "Update a single model's mutable fields by provider ID or slug (requires admin token)", + ) .option("-t, --admin-token ", "Admin session token") .option( "--forwarded-model-id ", diff --git a/src/types.ts b/src/types.ts index 09d8fd7..4457db2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -49,6 +49,7 @@ export interface ModelsResponse { export interface Provider { name?: string; id?: string; + slug?: string | null; base_url?: string; url?: string; model_count?: number;