import { PROVIDER_IDS, providerCatalog, providerSecretUrl, type ProviderId, } from './providers.ts' import { defaultSecretName } from './providers.ts' import { optionalString, parseProviderId, inputRecord } from './validation.ts' export type GuideInput = { provider?: string account?: string apiKeySecret?: string baseUrl?: string } function providerGuide(id: ProviderId, input: GuideInput) { const entry = providerCatalog(id) const secret = defaultSecretName(id, input.account, input.apiKeySecret) const host = id === 'openai-compatible' && input.baseUrl ? new URL(input.baseUrl).host : undefined return { id, label: entry.label, secret, hosts: host ? [host] : entry.hosts, defaultModel: entry.defaultModel || null, secretUrl: providerSecretUrl(id, secret, host), docs: entry.docs, console: entry.console || null, } } /** Agent-usable setup URLs and provider console steps for this package. */ export default async function guide(params: GuideInput = {}) { const parsed = inputRecord(params ?? {}) const provider = parseProviderId(optionalString(parsed, 'provider')) const account = optionalString(parsed, 'account') const apiKeySecret = optionalString(parsed, 'apiKeySecret') const baseUrl = optionalString(parsed, 'baseUrl') const input = { account, apiKeySecret, baseUrl } const providers = (provider ? [provider] : PROVIDER_IDS).map((id) => providerGuide(id, input), ) return { auth: 'secret-backed-api-key', oauth: false, jobs: false, providers, steps: [ 'Pick one provider and create an API key in that provider console. Never paste the key into chat.', 'Save it at the matching secretUrl and approve the listed host(s).', 'Optional: after forking, store provider/model/baseUrl/cloudflareAccountId via ./settings with confirm: true. Live @kody/ai storage is the platform bucket.', 'This package never creates a Cloudflare AI Gateway and never bakes in account ids or keys.', 'Invoke kody:@kody/ai/smoke-test to verify setup. Completions are live when you pass messages; pass dryRun: true to preview.', 'Host packages that need their own secret allowlists should call runModelStep and execute tools locally.', ], multiAccount: 'Pass account: "work" to use openaiApiKey-work (or the matching provider secret).', } }