@@ -64,7 +64,10 @@
6464 "description": "Model configurations for different model types"
6565 },
6666 "providers": {
67− "$ref": "#/$defs/Map[string,github.com/charmbracelet/crush/internal/config.ProviderConfig]",
67+ "additionalProperties": {
68+ "$ref": "#/$defs/ProviderConfig"
69+ },
70+ "type": "object",
6871 "description": "AI provider configurations"
6972 },
7073 "mcp": {
@@ -262,8 +265,88 @@
262265 },
263266 "type": "object"
264267 },
265− "Map[string,github.com/charmbracelet/crush/internal/config.ProviderConfig]": {
266− "properties": {},
268+ "Model": {
269+ "properties": {
270+ "id": {
271+ "type": "string"
272+ },
273+ "name": {
274+ "type": "string"
275+ },
276+ "cost_per_1m_in": {
277+ "type": "number"
278+ },
279+ "cost_per_1m_out": {
280+ "type": "number"
281+ },
282+ "cost_per_1m_in_cached": {
283+ "type": "number"
284+ },
285+ "cost_per_1m_out_cached": {
286+ "type": "number"
287+ },
288+ "context_window": {
289+ "type": "integer"
290+ },
291+ "default_max_tokens": {
292+ "type": "integer"
293+ },
294+ "can_reason": {
295+ "type": "boolean"
296+ },
297+ "reasoning_levels": {
298+ "items": {
299+ "type": "string"
300+ },
301+ "type": "array"
302+ },
303+ "default_reasoning_effort": {
304+ "type": "string"
305+ },
306+ "supports_attachments": {
307+ "type": "boolean"
308+ },
309+ "options": {
310+ "$ref": "#/$defs/ModelOptions"
311+ }
312+ },
313+ "additionalProperties": false,
314+ "type": "object",
315+ "required": [
316+ "id",
317+ "name",
318+ "cost_per_1m_in",
319+ "cost_per_1m_out",
320+ "cost_per_1m_in_cached",
321+ "cost_per_1m_out_cached",
322+ "context_window",
323+ "default_max_tokens",
324+ "can_reason",
325+ "supports_attachments",
326+ "options"
327+ ]
328+ },
329+ "ModelOptions": {
330+ "properties": {
331+ "temperature": {
332+ "type": "number"
333+ },
334+ "top_p": {
335+ "type": "number"
336+ },
337+ "top_k": {
338+ "type": "integer"
339+ },
340+ "frequency_penalty": {
341+ "type": "number"
342+ },
343+ "presence_penalty": {
344+ "type": "number"
345+ },
346+ "provider_options": {
347+ "type": "object"
348+ }
349+ },
267350 "additionalProperties": false,
268351 "type": "object"
269352 },
@@ -405,6 +488,89 @@
405488 "additionalProperties": false,
406489 "type": "object"
407490 },
491+ "ProviderConfig": {
492+ "properties": {
493+ "id": {
494+ "type": "string",
495+ "description": "Unique identifier for the provider",
496+ "examples": [
497+ "openai"
498+ ]
499+ },
500+ "name": {
501+ "type": "string",
502+ "description": "Human-readable name for the provider",
503+ "examples": [
504+ "OpenAI"
505+ ]
506+ },
507+ "base_url": {
508+ "type": "string",
509+ "format": "uri",
510+ "description": "Base URL for the provider's API",
511+ "examples": [
512+ "https://api.openai.com/v1"
513+ ]
514+ },
515+ "type": {
516+ "type": "string",
517+ "enum": [
518+ "openai",
519+ "openai-compat",
520+ "anthropic",
521+ "gemini",
522+ "azure",
523+ "vertexai"
524+ ],
525+ "description": "Provider type that determines the API format",
526+ "default": "openai"
527+ },
528+ "api_key": {
529+ "type": "string",
530+ "description": "API key for authentication with the provider",
531+ "examples": [
532+ "$OPENAI_API_KEY"
533+ ]
534+ },
535+ "oauth": {
536+ "$ref": "#/$defs/Token",
537+ "description": "OAuth2 token for authentication with the provider"
538+ },
539+ "disable": {
540+ "type": "boolean",
541+ "description": "Whether this provider is disabled",
542+ "default": false
543+ },
544+ "system_prompt_prefix": {
545+ "type": "string",
546+ "description": "Custom prefix to add to system prompts for this provider"
547+ },
548+ "extra_headers": {
549+ "additionalProperties": {
550+ "type": "string"
551+ },
552+ "type": "object",
553+ "description": "Additional HTTP headers to send with requests"
554+ },
555+ "extra_body": {
556+ "type": "object",
557+ "description": "Additional fields to include in request bodies"
558+ },
559+ "provider_options": {
560+ "type": "object",
561+ "description": "Additional provider-specific options for this provider"
562+ },
563+ "models": {
564+ "items": {
565+ "$ref": "#/$defs/Model"
566+ },
567+ "type": "array",
568+ "description": "List of models available from this provider"
569+ }
570+ },
571+ "additionalProperties": false,
572+ "type": "object"
573+ },
408574 "SelectedModel": {
409575 "properties": {
410576 "model": {
@@ -515,6 +681,30 @@
515681 "completions"
516682 ]
517683 },
684+ "Token": {
685+ "properties": {
686+ "access_token": {
687+ "type": "string"
688+ },
689+ "refresh_token": {
690+ "type": "string"
691+ },
692+ "expires_in": {
693+ "type": "integer"
694+ },
695+ "expires_at": {
696+ "type": "integer"
697+ }
698+ },
699+ "additionalProperties": false,
700+ "type": "object",
701+ "required": [
702+ "access_token",
703+ "refresh_token",
704+ "expires_in",
705+ "expires_at"
706+ ]
707+ },
518708 "ToolGrep": {
519709 "properties": {
520710 "timeout": {