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).',
}
}