{"repo": "chrisbanes/verity", "files": {"verity/cli/src/main/kotlin/me/chrisbanes/verity/cli/VerityProvider.kt": {"0e61eda0d58e0cc6301d198d5efd23bd2e32b765": {"t": 1785745720.5389357, "n": 12781, "h": "440dd2016d1e5e8b", "c": "package me.chrisbanes.verity.cli\n\nimport ai.koog.prompt.executor.clients.LLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicLLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicModels\nimport ai.koog.prompt.executor.clients.bedrock.BedrockLLMClient\nimport ai.koog.prompt.executor.clients.bedrock.BedrockModels\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeLLMClient\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeModels\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekLLMClient\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekModels\nimport ai.koog.prompt.executor.clients.google.GoogleLLMClient\nimport ai.koog.prompt.executor.clients.google.GoogleModels\nimport ai.koog.prompt.executor.clients.mistralai.MistralAILLMClient\nimport ai.koog.prompt.executor.clients.mistralai.MistralAIModels\nimport ai.koog.prompt.executor.clients.openai.OpenAILLMClient\nimport ai.koog.prompt.executor.clients.openai.OpenAIModels\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterLLMClient\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterModels\nimport ai.koog.prompt.executor.ollama.client.OllamaClient\nimport ai.koog.prompt.executor.ollama.client.OllamaModels\nimport ai.koog.prompt.llm.LLModel\nimport aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider\n\n/**\n * Represents a supported LLM provider for Verity.\n *\n * Each subclass specifies the provider's name, default models, authentication requirements,\n * and how to create the underlying Koog LLM client.\n */\nsealed class VerityProvider {\n /** CLI/config identifier for this provider. */\n abstract val name: String\n\n /** Cheap/fast model for YAML generation (navigator). */\n abstract val defaultNavigatorModel: LLModel\n\n /** Most capable model for assertion evaluation (inspector). */\n abstract val defaultInspectorModel: LLModel\n\n /** Environment variable name for the API key. */\n abstract val envVar: String\n\n /** Whether an API key is required to use this provider. False only for Ollama. */\n abstract val requiresAuth: Boolean\n\n /** All known chat models for this provider. */\n abstract fun allModels(): List\n\n /** Creates the Koog LLM client for this provider using the given API key (or host URL for Ollama). */\n abstract fun createClient(apiKey: String): LLMClient\n\n /** Looks up a model by its ID string, throws [IllegalStateException] if not found. */\n fun findModel(id: String): LLModel {\n val models = allModels()\n return models.find { it.id == id }\n ?: error(\"Unknown model '$id' for provider '$name'. Available: ${models.map { it.id }}\")\n }\n\n object Anthropic : VerityProvider() {\n override val name = \"anthropic\"\n override val defaultNavigatorModel: LLModel = AnthropicModels.Haiku_4_5\n override val defaultInspectorModel: LLModel = AnthropicModels.Opus_4_5\n override val envVar = \"ANTHROPIC_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n AnthropicModels.Sonnet_4,\n AnthropicModels.Opus_4,\n AnthropicModels.Opus_4_1,\n AnthropicModels.Opus_4_5,\n AnthropicModels.Opus_4_6,\n AnthropicModels.Opus_4_7,\n AnthropicModels.Sonnet_4_5,\n AnthropicModels.Sonnet_4_6,\n AnthropicModels.Haiku_4_5,\n )\n\n override fun createClient(apiKey: String): AnthropicLLMClient = AnthropicLLMClient(apiKey)\n }\n\n object OpenAI : VerityProvider() {\n override val name = \"openai\"\n override val defaultNavigatorModel: LLModel = OpenAIModels.Chat.GPT4oMini\n override val defaultInspectorModel: LLModel = OpenAIModels.Chat.GPT4o\n override val envVar = \"OPENAI_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenAIModels.Chat.GPT4o,\n OpenAIModels.Chat.GPT4oMini,\n OpenAIModels.Chat.GPT4_1,\n OpenAIModels.Chat.GPT4_1Nano,\n OpenAIModels.Chat.GPT4_1Mini,\n OpenAIModels.Chat.O1,\n OpenAIModels.Chat.O3,\n OpenAIModels.Chat.O3Mini,\n OpenAIModels.Chat.O4Mini,\n OpenAIModels.Chat.GPT5,\n OpenAIModels.Chat.GPT5Mini,\n OpenAIModels.Chat.GPT5Nano,\n OpenAIModels.Chat.GPT5Codex,\n OpenAIModels.Chat.GPT5Pro,\n OpenAIModels.Chat.GPT5_1,\n OpenAIModels.Chat.GPT5_1Codex,\n OpenAIModels.Chat.GPT5_2,\n OpenAIModels.Chat.GPT5_2Pro,\n )\n\n override fun createClient(apiKey: String): OpenAILLMClient = OpenAILLMClient(apiKey)\n }\n\n object Google : VerityProvider() {\n override val name = \"google\"\n override val defaultNavigatorModel: LLModel = GoogleModels.Gemini2_5FlashLite\n override val defaultInspectorModel: LLModel = GoogleModels.Gemini2_5Pro\n override val envVar = \"GOOGLE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n GoogleModels.Gemini2_0FlashLite001,\n GoogleModels.Gemini2_5Pro,\n GoogleModels.Gemini2_5Flash,\n GoogleModels.Gemini2_5FlashLite,\n GoogleModels.Gemini3_Flash_Preview,\n GoogleModels.Gemini3_Pro_Preview,\n )\n\n override fun createClient(apiKey: String): GoogleLLMClient = GoogleLLMClient(apiKey)\n }\n\n object OpenRouter : VerityProvider() {\n override val name = \"openrouter\"\n override val defaultNavigatorModel: LLModel = OpenRouterModels.Phi4Reasoning\n override val defaultInspectorModel: LLModel = OpenRouterModels.Claude4_5Opus\n override val envVar = \"OPENROUTER_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenRouterModels.Phi4Reasoning,\n OpenRouterModels.Claude3Opus,\n OpenRouterModels.Claude3Sonnet,\n OpenRouterModels.Claude3Haiku,\n OpenRouterModels.Claude3_5Sonnet,\n OpenRouterModels.Claude3_7Sonnet,\n OpenRouterModels.Claude4Sonnet,\n OpenRouterModels.Claude4_1Opus,\n OpenRouterModels.Claude4_5Haiku,\n OpenRouterModels.Claude4_5Sonnet,\n OpenRouterModels.Claude4_5Opus,\n OpenRouterModels.Claude3VisionSonnet,\n OpenRouterModels.Claude3VisionOpus,\n OpenRouterModels.Claude3VisionHaiku,\n OpenRouterModels.GPT35Turbo,\n OpenRouterModels.GPT4,\n OpenRouterModels.GPT4o,\n OpenRouterModels.GPT4oMini,\n OpenRouterModels.GPT4Turbo,\n OpenRouterModels.GPT5,\n OpenRouterModels.GPT5Mini,\n OpenRouterModels.GPT5Nano,\n OpenRouterModels.GPT5Chat,\n OpenRouterModels.GPT_OSS_120b,\n OpenRouterModels.GPT5_2,\n OpenRouterModels.GPT5_2Pro,\n OpenRouterModels.Llama3,\n OpenRouterModels.Llama3Instruct,\n OpenRouterModels.Mistral7B,\n OpenRouterModels.Mixtral8x7B,\n OpenRouterModels.DeepSeekV30324,\n OpenRouterModels.Gemini2_5FlashLite,\n OpenRouterModels.Gemini2_5Flash,\n OpenRouterModels.Gemini2_5Pro,\n OpenRouterModels.Qwen2_5,\n OpenRouterModels.Qwen3VL,\n )\n\n override fun createClient(apiKey: String): OpenRouterLLMClient = OpenRouterLLMClient(apiKey)\n }\n\n object Bedrock : VerityProvider() {\n override val name = \"bedrock\"\n override val defaultNavigatorModel: LLModel = BedrockModels.AnthropicClaude4_5Haiku\n override val defaultInspectorModel: LLModel = BedrockModels.AnthropicClaude4_5Sonnet\n override val envVar = \"AWS_ACCESS_KEY_ID\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n BedrockModels.AnthropicClaude4Opus,\n BedrockModels.AnthropicClaude41Opus,\n BedrockModels.AnthropicClaude45Opus,\n BedrockModels.AnthropicClaude46Opus,\n BedrockModels.AnthropicClaude47Opus,\n BedrockModels.AnthropicClaude4Sonnet,\n BedrockModels.AnthropicClaude4_5Sonnet,\n BedrockModels.AnthropicClaude4_6Sonnet,\n BedrockModels.AnthropicClaude4_5Haiku,\n BedrockModels.AmazonNovaMicro,\n BedrockModels.AmazonNovaLite,\n BedrockModels.AmazonNovaPro,\n BedrockModels.AmazonNovaPremier,\n BedrockModels.MetaLlama3_0_8BInstruct,\n BedrockModels.MetaLlama3_0_70BInstruct,\n BedrockModels.MetaLlama3_1_8BInstruct,\n BedrockModels.MetaLlama3_1_70BInstruct,\n BedrockModels.MetaLlama3_1_405BInstruct,\n BedrockModels.MetaLlama3_2_1BInstruct,\n BedrockModels.MetaLlama3_2_3BInstruct,\n BedrockModels.MetaLlama3_2_11BInstruct,\n BedrockModels.MetaLlama3_2_90BInstruct,\n BedrockModels.MetaLlama3_3_70BInstruct,\n BedrockModels.MoonshotKimiK2Thinking,\n BedrockModels.MoonshotKimiK2_5,\n BedrockModels.MiniMaxM2_5,\n BedrockModels.OpenAIGptOss120B,\n BedrockModels.OpenAIGptOss20B,\n BedrockModels.GoogleGemma3_4BIt,\n BedrockModels.GoogleGemma3_12BIt,\n BedrockModels.GoogleGemma3_27BIt,\n )\n\n override fun createClient(apiKey: String): BedrockLLMClient = createClient(apiKey, System.getenv(\"AWS_SECRET_ACCESS_KEY\"))\n\n internal fun createClient(apiKey: String, awsSecretKey: String?): BedrockLLMClient {\n val secret = awsSecretKey\n ?: error(\"AWS_SECRET_ACCESS_KEY environment variable is required for the Bedrock provider\")\n val credProvider =\n StaticCredentialsProvider {\n accessKeyId = apiKey\n secretAccessKey = secret\n }\n return BedrockLLMClient(identityProvider = credProvider)\n }\n }\n\n object DeepSeek : VerityProvider() {\n override val name = \"deepseek\"\n override val defaultNavigatorModel: LLModel = DeepSeekModels.DeepSeekV4Flash\n override val defaultInspectorModel: LLModel = DeepSeekModels.DeepSeekV4Pro\n override val envVar = \"DEEPSEEK_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DeepSeekModels.DeepSeekV4Flash,\n DeepSeekModels.DeepSeekV4Pro,\n )\n\n override fun createClient(apiKey: String): DeepSeekLLMClient = DeepSeekLLMClient(apiKey)\n }\n\n object MistralAI : VerityProvider() {\n override val name = \"mistralai\"\n override val defaultNavigatorModel: LLModel = MistralAIModels.Chat.MistralSmall2\n override val defaultInspectorModel: LLModel = MistralAIModels.Chat.MagistralMedium12\n override val envVar = \"MISTRAL_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n MistralAIModels.Chat.MistralMedium31,\n MistralAIModels.Chat.MistralLarge21,\n MistralAIModels.Chat.MistralSmall2,\n MistralAIModels.Chat.MagistralMedium12,\n MistralAIModels.Chat.Codestral,\n MistralAIModels.Chat.DevstralMedium,\n )\n\n override fun createClient(apiKey: String): MistralAILLMClient = MistralAILLMClient(apiKey)\n }\n\n object Ollama : VerityProvider() {\n override val name = \"ollama\"\n override val defaultNavigatorModel: LLModel = OllamaModels.Meta.LLAMA_3_2_3B\n override val defaultInspectorModel: LLModel = OllamaModels.Meta.LLAMA_4_SCOUT\n override val envVar = \"OLLAMA_HOST\"\n override val requiresAuth = false\n\n override fun allModels(): List = listOf(\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_8B,\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_70B,\n OllamaModels.Meta.LLAMA_3_2_3B,\n OllamaModels.Meta.LLAMA_3_2,\n OllamaModels.Meta.LLAMA_4_SCOUT,\n OllamaModels.Meta.LLAMA_4,\n OllamaModels.Alibaba.QWEN_2_5_05B,\n OllamaModels.Alibaba.QWEN_3_06B,\n OllamaModels.Alibaba.QWQ_32B,\n OllamaModels.Alibaba.QWQ,\n OllamaModels.Alibaba.QWEN_CODER_2_5_32B,\n OllamaModels.Granite.GRANITE_3_2_VISION,\n )\n\n override fun createClient(apiKey: String): OllamaClient = OllamaClient(baseUrl = apiKey.ifBlank { \"http://localhost:11434\" })\n }\n\n object DashScope : VerityProvider() {\n override val name = \"dashscope\"\n override val defaultNavigatorModel: LLModel = DashscopeModels.QWEN_FLASH\n override val defaultInspectorModel: LLModel = DashscopeModels.QWEN3_MAX\n override val envVar = \"DASHSCOPE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DashscopeModels.QWEN_FLASH,\n DashscopeModels.QWEN3_OMNI_FLASH,\n DashscopeModels.QWEN_PLUS,\n DashscopeModels.QWEN_PLUS_LATEST,\n DashscopeModels.QWEN3_CODER_PLUS,\n DashscopeModels.QWEN3_CODER_FLASH,\n DashscopeModels.QWEN3_MAX,\n )\n\n override fun createClient(apiKey: String): DashscopeLLMClient = DashscopeLLMClient(apiKey)\n }\n\n companion object {\n /** All 9 supported providers. */\n val all: List =\n listOf(\n Anthropic,\n OpenAI,\n Google,\n OpenRouter,\n Bedrock,\n DeepSeek,\n MistralAI,\n Ollama,\n DashScope,\n )\n\n /** Looks up a provider by name, throws [IllegalStateException] for unknown names. */\n fun fromName(name: String): VerityProvider = all.find { it.name == name }\n ?: error(\n \"Unknown provider '$name'. Available providers: ${all.map { it.name }}\",\n )\n }\n}\n"}, "5dc2d4f36ec3856118bc49eabdbe61abaaa9d53b": {"t": 1785755919.7073123, "n": 12781, "h": "440dd2016d1e5e8b", "c": "package me.chrisbanes.verity.cli\n\nimport ai.koog.prompt.executor.clients.LLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicLLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicModels\nimport ai.koog.prompt.executor.clients.bedrock.BedrockLLMClient\nimport ai.koog.prompt.executor.clients.bedrock.BedrockModels\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeLLMClient\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeModels\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekLLMClient\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekModels\nimport ai.koog.prompt.executor.clients.google.GoogleLLMClient\nimport ai.koog.prompt.executor.clients.google.GoogleModels\nimport ai.koog.prompt.executor.clients.mistralai.MistralAILLMClient\nimport ai.koog.prompt.executor.clients.mistralai.MistralAIModels\nimport ai.koog.prompt.executor.clients.openai.OpenAILLMClient\nimport ai.koog.prompt.executor.clients.openai.OpenAIModels\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterLLMClient\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterModels\nimport ai.koog.prompt.executor.ollama.client.OllamaClient\nimport ai.koog.prompt.executor.ollama.client.OllamaModels\nimport ai.koog.prompt.llm.LLModel\nimport aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider\n\n/**\n * Represents a supported LLM provider for Verity.\n *\n * Each subclass specifies the provider's name, default models, authentication requirements,\n * and how to create the underlying Koog LLM client.\n */\nsealed class VerityProvider {\n /** CLI/config identifier for this provider. */\n abstract val name: String\n\n /** Cheap/fast model for YAML generation (navigator). */\n abstract val defaultNavigatorModel: LLModel\n\n /** Most capable model for assertion evaluation (inspector). */\n abstract val defaultInspectorModel: LLModel\n\n /** Environment variable name for the API key. */\n abstract val envVar: String\n\n /** Whether an API key is required to use this provider. False only for Ollama. */\n abstract val requiresAuth: Boolean\n\n /** All known chat models for this provider. */\n abstract fun allModels(): List\n\n /** Creates the Koog LLM client for this provider using the given API key (or host URL for Ollama). */\n abstract fun createClient(apiKey: String): LLMClient\n\n /** Looks up a model by its ID string, throws [IllegalStateException] if not found. */\n fun findModel(id: String): LLModel {\n val models = allModels()\n return models.find { it.id == id }\n ?: error(\"Unknown model '$id' for provider '$name'. Available: ${models.map { it.id }}\")\n }\n\n object Anthropic : VerityProvider() {\n override val name = \"anthropic\"\n override val defaultNavigatorModel: LLModel = AnthropicModels.Haiku_4_5\n override val defaultInspectorModel: LLModel = AnthropicModels.Opus_4_5\n override val envVar = \"ANTHROPIC_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n AnthropicModels.Sonnet_4,\n AnthropicModels.Opus_4,\n AnthropicModels.Opus_4_1,\n AnthropicModels.Opus_4_5,\n AnthropicModels.Opus_4_6,\n AnthropicModels.Opus_4_7,\n AnthropicModels.Sonnet_4_5,\n AnthropicModels.Sonnet_4_6,\n AnthropicModels.Haiku_4_5,\n )\n\n override fun createClient(apiKey: String): AnthropicLLMClient = AnthropicLLMClient(apiKey)\n }\n\n object OpenAI : VerityProvider() {\n override val name = \"openai\"\n override val defaultNavigatorModel: LLModel = OpenAIModels.Chat.GPT4oMini\n override val defaultInspectorModel: LLModel = OpenAIModels.Chat.GPT4o\n override val envVar = \"OPENAI_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenAIModels.Chat.GPT4o,\n OpenAIModels.Chat.GPT4oMini,\n OpenAIModels.Chat.GPT4_1,\n OpenAIModels.Chat.GPT4_1Nano,\n OpenAIModels.Chat.GPT4_1Mini,\n OpenAIModels.Chat.O1,\n OpenAIModels.Chat.O3,\n OpenAIModels.Chat.O3Mini,\n OpenAIModels.Chat.O4Mini,\n OpenAIModels.Chat.GPT5,\n OpenAIModels.Chat.GPT5Mini,\n OpenAIModels.Chat.GPT5Nano,\n OpenAIModels.Chat.GPT5Codex,\n OpenAIModels.Chat.GPT5Pro,\n OpenAIModels.Chat.GPT5_1,\n OpenAIModels.Chat.GPT5_1Codex,\n OpenAIModels.Chat.GPT5_2,\n OpenAIModels.Chat.GPT5_2Pro,\n )\n\n override fun createClient(apiKey: String): OpenAILLMClient = OpenAILLMClient(apiKey)\n }\n\n object Google : VerityProvider() {\n override val name = \"google\"\n override val defaultNavigatorModel: LLModel = GoogleModels.Gemini2_5FlashLite\n override val defaultInspectorModel: LLModel = GoogleModels.Gemini2_5Pro\n override val envVar = \"GOOGLE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n GoogleModels.Gemini2_0FlashLite001,\n GoogleModels.Gemini2_5Pro,\n GoogleModels.Gemini2_5Flash,\n GoogleModels.Gemini2_5FlashLite,\n GoogleModels.Gemini3_Flash_Preview,\n GoogleModels.Gemini3_Pro_Preview,\n )\n\n override fun createClient(apiKey: String): GoogleLLMClient = GoogleLLMClient(apiKey)\n }\n\n object OpenRouter : VerityProvider() {\n override val name = \"openrouter\"\n override val defaultNavigatorModel: LLModel = OpenRouterModels.Phi4Reasoning\n override val defaultInspectorModel: LLModel = OpenRouterModels.Claude4_5Opus\n override val envVar = \"OPENROUTER_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenRouterModels.Phi4Reasoning,\n OpenRouterModels.Claude3Opus,\n OpenRouterModels.Claude3Sonnet,\n OpenRouterModels.Claude3Haiku,\n OpenRouterModels.Claude3_5Sonnet,\n OpenRouterModels.Claude3_7Sonnet,\n OpenRouterModels.Claude4Sonnet,\n OpenRouterModels.Claude4_1Opus,\n OpenRouterModels.Claude4_5Haiku,\n OpenRouterModels.Claude4_5Sonnet,\n OpenRouterModels.Claude4_5Opus,\n OpenRouterModels.Claude3VisionSonnet,\n OpenRouterModels.Claude3VisionOpus,\n OpenRouterModels.Claude3VisionHaiku,\n OpenRouterModels.GPT35Turbo,\n OpenRouterModels.GPT4,\n OpenRouterModels.GPT4o,\n OpenRouterModels.GPT4oMini,\n OpenRouterModels.GPT4Turbo,\n OpenRouterModels.GPT5,\n OpenRouterModels.GPT5Mini,\n OpenRouterModels.GPT5Nano,\n OpenRouterModels.GPT5Chat,\n OpenRouterModels.GPT_OSS_120b,\n OpenRouterModels.GPT5_2,\n OpenRouterModels.GPT5_2Pro,\n OpenRouterModels.Llama3,\n OpenRouterModels.Llama3Instruct,\n OpenRouterModels.Mistral7B,\n OpenRouterModels.Mixtral8x7B,\n OpenRouterModels.DeepSeekV30324,\n OpenRouterModels.Gemini2_5FlashLite,\n OpenRouterModels.Gemini2_5Flash,\n OpenRouterModels.Gemini2_5Pro,\n OpenRouterModels.Qwen2_5,\n OpenRouterModels.Qwen3VL,\n )\n\n override fun createClient(apiKey: String): OpenRouterLLMClient = OpenRouterLLMClient(apiKey)\n }\n\n object Bedrock : VerityProvider() {\n override val name = \"bedrock\"\n override val defaultNavigatorModel: LLModel = BedrockModels.AnthropicClaude4_5Haiku\n override val defaultInspectorModel: LLModel = BedrockModels.AnthropicClaude4_5Sonnet\n override val envVar = \"AWS_ACCESS_KEY_ID\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n BedrockModels.AnthropicClaude4Opus,\n BedrockModels.AnthropicClaude41Opus,\n BedrockModels.AnthropicClaude45Opus,\n BedrockModels.AnthropicClaude46Opus,\n BedrockModels.AnthropicClaude47Opus,\n BedrockModels.AnthropicClaude4Sonnet,\n BedrockModels.AnthropicClaude4_5Sonnet,\n BedrockModels.AnthropicClaude4_6Sonnet,\n BedrockModels.AnthropicClaude4_5Haiku,\n BedrockModels.AmazonNovaMicro,\n BedrockModels.AmazonNovaLite,\n BedrockModels.AmazonNovaPro,\n BedrockModels.AmazonNovaPremier,\n BedrockModels.MetaLlama3_0_8BInstruct,\n BedrockModels.MetaLlama3_0_70BInstruct,\n BedrockModels.MetaLlama3_1_8BInstruct,\n BedrockModels.MetaLlama3_1_70BInstruct,\n BedrockModels.MetaLlama3_1_405BInstruct,\n BedrockModels.MetaLlama3_2_1BInstruct,\n BedrockModels.MetaLlama3_2_3BInstruct,\n BedrockModels.MetaLlama3_2_11BInstruct,\n BedrockModels.MetaLlama3_2_90BInstruct,\n BedrockModels.MetaLlama3_3_70BInstruct,\n BedrockModels.MoonshotKimiK2Thinking,\n BedrockModels.MoonshotKimiK2_5,\n BedrockModels.MiniMaxM2_5,\n BedrockModels.OpenAIGptOss120B,\n BedrockModels.OpenAIGptOss20B,\n BedrockModels.GoogleGemma3_4BIt,\n BedrockModels.GoogleGemma3_12BIt,\n BedrockModels.GoogleGemma3_27BIt,\n )\n\n override fun createClient(apiKey: String): BedrockLLMClient = createClient(apiKey, System.getenv(\"AWS_SECRET_ACCESS_KEY\"))\n\n internal fun createClient(apiKey: String, awsSecretKey: String?): BedrockLLMClient {\n val secret = awsSecretKey\n ?: error(\"AWS_SECRET_ACCESS_KEY environment variable is required for the Bedrock provider\")\n val credProvider =\n StaticCredentialsProvider {\n accessKeyId = apiKey\n secretAccessKey = secret\n }\n return BedrockLLMClient(identityProvider = credProvider)\n }\n }\n\n object DeepSeek : VerityProvider() {\n override val name = \"deepseek\"\n override val defaultNavigatorModel: LLModel = DeepSeekModels.DeepSeekV4Flash\n override val defaultInspectorModel: LLModel = DeepSeekModels.DeepSeekV4Pro\n override val envVar = \"DEEPSEEK_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DeepSeekModels.DeepSeekV4Flash,\n DeepSeekModels.DeepSeekV4Pro,\n )\n\n override fun createClient(apiKey: String): DeepSeekLLMClient = DeepSeekLLMClient(apiKey)\n }\n\n object MistralAI : VerityProvider() {\n override val name = \"mistralai\"\n override val defaultNavigatorModel: LLModel = MistralAIModels.Chat.MistralSmall2\n override val defaultInspectorModel: LLModel = MistralAIModels.Chat.MagistralMedium12\n override val envVar = \"MISTRAL_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n MistralAIModels.Chat.MistralMedium31,\n MistralAIModels.Chat.MistralLarge21,\n MistralAIModels.Chat.MistralSmall2,\n MistralAIModels.Chat.MagistralMedium12,\n MistralAIModels.Chat.Codestral,\n MistralAIModels.Chat.DevstralMedium,\n )\n\n override fun createClient(apiKey: String): MistralAILLMClient = MistralAILLMClient(apiKey)\n }\n\n object Ollama : VerityProvider() {\n override val name = \"ollama\"\n override val defaultNavigatorModel: LLModel = OllamaModels.Meta.LLAMA_3_2_3B\n override val defaultInspectorModel: LLModel = OllamaModels.Meta.LLAMA_4_SCOUT\n override val envVar = \"OLLAMA_HOST\"\n override val requiresAuth = false\n\n override fun allModels(): List = listOf(\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_8B,\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_70B,\n OllamaModels.Meta.LLAMA_3_2_3B,\n OllamaModels.Meta.LLAMA_3_2,\n OllamaModels.Meta.LLAMA_4_SCOUT,\n OllamaModels.Meta.LLAMA_4,\n OllamaModels.Alibaba.QWEN_2_5_05B,\n OllamaModels.Alibaba.QWEN_3_06B,\n OllamaModels.Alibaba.QWQ_32B,\n OllamaModels.Alibaba.QWQ,\n OllamaModels.Alibaba.QWEN_CODER_2_5_32B,\n OllamaModels.Granite.GRANITE_3_2_VISION,\n )\n\n override fun createClient(apiKey: String): OllamaClient = OllamaClient(baseUrl = apiKey.ifBlank { \"http://localhost:11434\" })\n }\n\n object DashScope : VerityProvider() {\n override val name = \"dashscope\"\n override val defaultNavigatorModel: LLModel = DashscopeModels.QWEN_FLASH\n override val defaultInspectorModel: LLModel = DashscopeModels.QWEN3_MAX\n override val envVar = \"DASHSCOPE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DashscopeModels.QWEN_FLASH,\n DashscopeModels.QWEN3_OMNI_FLASH,\n DashscopeModels.QWEN_PLUS,\n DashscopeModels.QWEN_PLUS_LATEST,\n DashscopeModels.QWEN3_CODER_PLUS,\n DashscopeModels.QWEN3_CODER_FLASH,\n DashscopeModels.QWEN3_MAX,\n )\n\n override fun createClient(apiKey: String): DashscopeLLMClient = DashscopeLLMClient(apiKey)\n }\n\n companion object {\n /** All 9 supported providers. */\n val all: List =\n listOf(\n Anthropic,\n OpenAI,\n Google,\n OpenRouter,\n Bedrock,\n DeepSeek,\n MistralAI,\n Ollama,\n DashScope,\n )\n\n /** Looks up a provider by name, throws [IllegalStateException] for unknown names. */\n fun fromName(name: String): VerityProvider = all.find { it.name == name }\n ?: error(\n \"Unknown provider '$name'. Available providers: ${all.map { it.name }}\",\n )\n }\n}\n"}, "3e9afcfb79824ab924fc4756616e28f603506215": {"t": 1785755921.0299315, "n": 12585, "h": "26927bd9a61896b2", "c": "package me.chrisbanes.verity.cli\n\nimport ai.koog.prompt.executor.clients.LLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicLLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicModels\nimport ai.koog.prompt.executor.clients.bedrock.BedrockLLMClient\nimport ai.koog.prompt.executor.clients.bedrock.BedrockModels\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeLLMClient\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeModels\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekLLMClient\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekModels\nimport ai.koog.prompt.executor.clients.google.GoogleLLMClient\nimport ai.koog.prompt.executor.clients.google.GoogleModels\nimport ai.koog.prompt.executor.clients.mistralai.MistralAILLMClient\nimport ai.koog.prompt.executor.clients.mistralai.MistralAIModels\nimport ai.koog.prompt.executor.clients.openai.OpenAILLMClient\nimport ai.koog.prompt.executor.clients.openai.OpenAIModels\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterLLMClient\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterModels\nimport ai.koog.prompt.executor.ollama.client.OllamaClient\nimport ai.koog.prompt.executor.ollama.client.OllamaModels\nimport ai.koog.prompt.llm.LLModel\nimport aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider\n\n/**\n * Represents a supported LLM provider for Verity.\n *\n * Each subclass specifies the provider's name, default models, authentication requirements,\n * and how to create the underlying Koog LLM client.\n */\nsealed class VerityProvider {\n /** CLI/config identifier for this provider. */\n abstract val name: String\n\n /** Cheap/fast model for YAML generation (navigator). */\n abstract val defaultNavigatorModel: LLModel\n\n /** Most capable model for assertion evaluation (inspector). */\n abstract val defaultInspectorModel: LLModel\n\n /** Environment variable name for the API key. */\n abstract val envVar: String\n\n /** Whether an API key is required to use this provider. False only for Ollama. */\n abstract val requiresAuth: Boolean\n\n /** All known chat models for this provider. */\n abstract fun allModels(): List\n\n /** Creates the Koog LLM client for this provider using the given API key (or host URL for Ollama). */\n abstract fun createClient(apiKey: String): LLMClient\n\n /** Looks up a model by its ID string, throws [IllegalStateException] if not found. */\n fun findModel(id: String): LLModel {\n val models = allModels()\n return models.find { it.id == id }\n ?: error(\"Unknown model '$id' for provider '$name'. Available: ${models.map { it.id }}\")\n }\n\n object Anthropic : VerityProvider() {\n override val name = \"anthropic\"\n override val defaultNavigatorModel: LLModel = AnthropicModels.Haiku_4_5\n override val defaultInspectorModel: LLModel = AnthropicModels.Opus_4_5\n override val envVar = \"ANTHROPIC_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n AnthropicModels.Haiku_3,\n AnthropicModels.Sonnet_4,\n AnthropicModels.Opus_4,\n AnthropicModels.Opus_4_1,\n AnthropicModels.Opus_4_5,\n AnthropicModels.Opus_4_6,\n AnthropicModels.Sonnet_4_5,\n AnthropicModels.Sonnet_4_6,\n AnthropicModels.Haiku_4_5,\n )\n\n override fun createClient(apiKey: String): AnthropicLLMClient = AnthropicLLMClient(apiKey)\n }\n\n object OpenAI : VerityProvider() {\n override val name = \"openai\"\n override val defaultNavigatorModel: LLModel = OpenAIModels.Chat.GPT4oMini\n override val defaultInspectorModel: LLModel = OpenAIModels.Chat.GPT4o\n override val envVar = \"OPENAI_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenAIModels.Chat.GPT4o,\n OpenAIModels.Chat.GPT4oMini,\n OpenAIModels.Chat.GPT4_1,\n OpenAIModels.Chat.GPT4_1Nano,\n OpenAIModels.Chat.GPT4_1Mini,\n OpenAIModels.Chat.O1,\n OpenAIModels.Chat.O3,\n OpenAIModels.Chat.O3Mini,\n OpenAIModels.Chat.O4Mini,\n OpenAIModels.Chat.GPT5,\n OpenAIModels.Chat.GPT5Mini,\n OpenAIModels.Chat.GPT5Nano,\n OpenAIModels.Chat.GPT5Codex,\n OpenAIModels.Chat.GPT5Pro,\n OpenAIModels.Chat.GPT5_1,\n OpenAIModels.Chat.GPT5_1Codex,\n OpenAIModels.Chat.GPT5_2,\n OpenAIModels.Chat.GPT5_2Pro,\n )\n\n override fun createClient(apiKey: String): OpenAILLMClient = OpenAILLMClient(apiKey)\n }\n\n object Google : VerityProvider() {\n override val name = \"google\"\n override val defaultNavigatorModel: LLModel = GoogleModels.Gemini2_0FlashLite\n override val defaultInspectorModel: LLModel = GoogleModels.Gemini2_5Pro\n override val envVar = \"GOOGLE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n GoogleModels.Gemini2_0Flash,\n GoogleModels.Gemini2_0Flash001,\n GoogleModels.Gemini2_0FlashLite,\n GoogleModels.Gemini2_0FlashLite001,\n GoogleModels.Gemini2_5Pro,\n GoogleModels.Gemini2_5Flash,\n GoogleModels.Gemini2_5FlashLite,\n GoogleModels.Gemini3_Pro_Preview,\n )\n\n override fun createClient(apiKey: String): GoogleLLMClient = GoogleLLMClient(apiKey)\n }\n\n object OpenRouter : VerityProvider() {\n override val name = \"openrouter\"\n override val defaultNavigatorModel: LLModel = OpenRouterModels.Phi4Reasoning\n override val defaultInspectorModel: LLModel = OpenRouterModels.Claude4_5Opus\n override val envVar = \"OPENROUTER_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenRouterModels.Phi4Reasoning,\n OpenRouterModels.Claude3Opus,\n OpenRouterModels.Claude3Sonnet,\n OpenRouterModels.Claude3Haiku,\n OpenRouterModels.Claude3_5Sonnet,\n OpenRouterModels.Claude3_7Sonnet,\n OpenRouterModels.Claude4Sonnet,\n OpenRouterModels.Claude4_1Opus,\n OpenRouterModels.Claude4_5Haiku,\n OpenRouterModels.Claude4_5Sonnet,\n OpenRouterModels.Claude4_5Opus,\n OpenRouterModels.Claude3VisionSonnet,\n OpenRouterModels.Claude3VisionOpus,\n OpenRouterModels.Claude3VisionHaiku,\n OpenRouterModels.GPT35Turbo,\n OpenRouterModels.GPT4,\n OpenRouterModels.GPT4o,\n OpenRouterModels.GPT4oMini,\n OpenRouterModels.GPT4Turbo,\n OpenRouterModels.GPT5,\n OpenRouterModels.GPT5Mini,\n OpenRouterModels.GPT5Nano,\n OpenRouterModels.GPT5Chat,\n OpenRouterModels.GPT_OSS_120b,\n OpenRouterModels.GPT5_2,\n OpenRouterModels.GPT5_2Pro,\n OpenRouterModels.Llama3,\n OpenRouterModels.Llama3Instruct,\n OpenRouterModels.Mistral7B,\n OpenRouterModels.Mixtral8x7B,\n OpenRouterModels.DeepSeekV30324,\n OpenRouterModels.Gemini2_5FlashLite,\n OpenRouterModels.Gemini2_5Flash,\n OpenRouterModels.Gemini2_5Pro,\n OpenRouterModels.Qwen2_5,\n OpenRouterModels.Qwen3VL,\n )\n\n override fun createClient(apiKey: String): OpenRouterLLMClient = OpenRouterLLMClient(apiKey)\n }\n\n object Bedrock : VerityProvider() {\n override val name = \"bedrock\"\n override val defaultNavigatorModel: LLModel = BedrockModels.AnthropicClaude4_5Haiku\n override val defaultInspectorModel: LLModel = BedrockModels.AnthropicClaude4_5Sonnet\n override val envVar = \"AWS_ACCESS_KEY_ID\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n BedrockModels.AnthropicClaude3Haiku,\n BedrockModels.AnthropicClaude4Opus,\n BedrockModels.AnthropicClaude41Opus,\n BedrockModels.AnthropicClaude45Opus,\n BedrockModels.AnthropicClaude46Opus,\n BedrockModels.AnthropicClaude4Sonnet,\n BedrockModels.AnthropicClaude4_5Sonnet,\n BedrockModels.AnthropicClaude4_6Sonnet,\n BedrockModels.AnthropicClaude4_5Haiku,\n BedrockModels.AmazonNovaMicro,\n BedrockModels.AmazonNovaLite,\n BedrockModels.AmazonNovaPro,\n BedrockModels.AmazonNovaPremier,\n BedrockModels.MetaLlama3_0_8BInstruct,\n BedrockModels.MetaLlama3_0_70BInstruct,\n BedrockModels.MetaLlama3_1_8BInstruct,\n BedrockModels.MetaLlama3_1_70BInstruct,\n BedrockModels.MetaLlama3_1_405BInstruct,\n BedrockModels.MetaLlama3_2_1BInstruct,\n BedrockModels.MetaLlama3_2_3BInstruct,\n BedrockModels.MetaLlama3_2_11BInstruct,\n BedrockModels.MetaLlama3_2_90BInstruct,\n BedrockModels.MetaLlama3_3_70BInstruct,\n BedrockModels.MoonshotKimiK2Thinking,\n )\n\n override fun createClient(apiKey: String): BedrockLLMClient = createClient(apiKey, System.getenv(\"AWS_SECRET_ACCESS_KEY\"))\n\n internal fun createClient(apiKey: String, awsSecretKey: String?): BedrockLLMClient {\n val secret = awsSecretKey\n ?: error(\"AWS_SECRET_ACCESS_KEY environment variable is required for the Bedrock provider\")\n val credProvider =\n StaticCredentialsProvider {\n accessKeyId = apiKey\n secretAccessKey = secret\n }\n return BedrockLLMClient(identityProvider = credProvider)\n }\n }\n\n object DeepSeek : VerityProvider() {\n override val name = \"deepseek\"\n override val defaultNavigatorModel: LLModel = DeepSeekModels.DeepSeekChat\n override val defaultInspectorModel: LLModel = DeepSeekModels.DeepSeekReasoner\n override val envVar = \"DEEPSEEK_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DeepSeekModels.DeepSeekChat,\n DeepSeekModels.DeepSeekReasoner,\n )\n\n override fun createClient(apiKey: String): DeepSeekLLMClient = DeepSeekLLMClient(apiKey)\n }\n\n object MistralAI : VerityProvider() {\n override val name = \"mistralai\"\n override val defaultNavigatorModel: LLModel = MistralAIModels.Chat.MistralSmall2\n override val defaultInspectorModel: LLModel = MistralAIModels.Chat.MagistralMedium12\n override val envVar = \"MISTRAL_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n MistralAIModels.Chat.MistralMedium31,\n MistralAIModels.Chat.MistralLarge21,\n MistralAIModels.Chat.MistralSmall2,\n MistralAIModels.Chat.MagistralMedium12,\n MistralAIModels.Chat.Codestral,\n MistralAIModels.Chat.DevstralMedium,\n )\n\n override fun createClient(apiKey: String): MistralAILLMClient = MistralAILLMClient(apiKey)\n }\n\n object Ollama : VerityProvider() {\n override val name = \"ollama\"\n override val defaultNavigatorModel: LLModel = OllamaModels.Meta.LLAMA_3_2_3B\n override val defaultInspectorModel: LLModel = OllamaModels.Meta.LLAMA_4_SCOUT\n override val envVar = \"OLLAMA_HOST\"\n override val requiresAuth = false\n\n override fun allModels(): List = listOf(\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_8B,\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_70B,\n OllamaModels.Meta.LLAMA_3_2_3B,\n OllamaModels.Meta.LLAMA_3_2,\n OllamaModels.Meta.LLAMA_4_SCOUT,\n OllamaModels.Meta.LLAMA_4,\n OllamaModels.Alibaba.QWEN_2_5_05B,\n OllamaModels.Alibaba.QWEN_3_06B,\n OllamaModels.Alibaba.QWQ_32B,\n OllamaModels.Alibaba.QWQ,\n OllamaModels.Alibaba.QWEN_CODER_2_5_32B,\n OllamaModels.Granite.GRANITE_3_2_VISION,\n )\n\n override fun createClient(apiKey: String): OllamaClient = OllamaClient(baseUrl = apiKey.ifBlank { \"http://localhost:11434\" })\n }\n\n object DashScope : VerityProvider() {\n override val name = \"dashscope\"\n override val defaultNavigatorModel: LLModel = DashscopeModels.QWEN_FLASH\n override val defaultInspectorModel: LLModel = DashscopeModels.QWEN3_MAX\n override val envVar = \"DASHSCOPE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DashscopeModels.QWEN_FLASH,\n DashscopeModels.QWEN3_OMNI_FLASH,\n DashscopeModels.QWEN_PLUS,\n DashscopeModels.QWEN_PLUS_LATEST,\n DashscopeModels.QWEN3_CODER_PLUS,\n DashscopeModels.QWEN3_CODER_FLASH,\n DashscopeModels.QWEN3_MAX,\n )\n\n override fun createClient(apiKey: String): DashscopeLLMClient = DashscopeLLMClient(apiKey)\n }\n\n companion object {\n /** All 9 supported providers. */\n val all: List =\n listOf(\n Anthropic,\n OpenAI,\n Google,\n OpenRouter,\n Bedrock,\n DeepSeek,\n MistralAI,\n Ollama,\n DashScope,\n )\n\n /** Looks up a provider by name, throws [IllegalStateException] for unknown names. */\n fun fromName(name: String): VerityProvider = all.find { it.name == name }\n ?: error(\n \"Unknown provider '$name'. Available providers: ${all.map { it.name }}\",\n )\n }\n}\n"}, "0c49e830dc4b6a1f03402cd40a0c01c4fdbfea00": {"t": 1785755922.4425285, "n": 12848, "h": "01263a099899dcdc", "c": "package me.chrisbanes.verity.cli\n\nimport ai.koog.prompt.executor.clients.LLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicLLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicModels\nimport ai.koog.prompt.executor.clients.bedrock.BedrockLLMClient\nimport ai.koog.prompt.executor.clients.bedrock.BedrockModels\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeLLMClient\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeModels\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekLLMClient\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekModels\nimport ai.koog.prompt.executor.clients.google.GoogleLLMClient\nimport ai.koog.prompt.executor.clients.google.GoogleModels\nimport ai.koog.prompt.executor.clients.mistralai.MistralAILLMClient\nimport ai.koog.prompt.executor.clients.mistralai.MistralAIModels\nimport ai.koog.prompt.executor.clients.openai.OpenAILLMClient\nimport ai.koog.prompt.executor.clients.openai.OpenAIModels\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterLLMClient\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterModels\nimport ai.koog.prompt.executor.ollama.client.OllamaClient\nimport ai.koog.prompt.executor.ollama.client.OllamaModels\nimport ai.koog.prompt.llm.LLModel\nimport aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider\n\n/**\n * Represents a supported LLM provider for Verity.\n *\n * Each subclass specifies the provider's name, default models, authentication requirements,\n * and how to create the underlying Koog LLM client.\n */\nsealed class VerityProvider {\n /** CLI/config identifier for this provider. */\n abstract val name: String\n\n /** Cheap/fast model for YAML generation (navigator). */\n abstract val defaultNavigatorModel: LLModel\n\n /** Most capable model for assertion evaluation (inspector). */\n abstract val defaultInspectorModel: LLModel\n\n /** Environment variable name for the API key. */\n abstract val envVar: String\n\n /** Whether an API key is required to use this provider. False only for Ollama. */\n abstract val requiresAuth: Boolean\n\n /** All known chat models for this provider. */\n abstract fun allModels(): List\n\n /** Creates the Koog LLM client for this provider using the given API key (or host URL for Ollama). */\n abstract fun createClient(apiKey: String): LLMClient\n\n /** Looks up a model by its ID string, throws [IllegalStateException] if not found. */\n fun findModel(id: String): LLModel {\n val models = allModels()\n return models.find { it.id == id }\n ?: error(\"Unknown model '$id' for provider '$name'. Available: ${models.map { it.id }}\")\n }\n\n object Anthropic : VerityProvider() {\n override val name = \"anthropic\"\n override val defaultNavigatorModel: LLModel = AnthropicModels.Haiku_4_5\n override val defaultInspectorModel: LLModel = AnthropicModels.Opus_4_5\n override val envVar = \"ANTHROPIC_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n AnthropicModels.Opus_3,\n AnthropicModels.Haiku_3,\n AnthropicModels.Sonnet_3_5,\n AnthropicModels.Haiku_3_5,\n AnthropicModels.Sonnet_3_7,\n AnthropicModels.Sonnet_4,\n AnthropicModels.Opus_4,\n AnthropicModels.Opus_4_1,\n AnthropicModels.Opus_4_5,\n AnthropicModels.Sonnet_4_5,\n AnthropicModels.Haiku_4_5,\n )\n\n override fun createClient(apiKey: String): AnthropicLLMClient = AnthropicLLMClient(apiKey)\n }\n\n object OpenAI : VerityProvider() {\n override val name = \"openai\"\n override val defaultNavigatorModel: LLModel = OpenAIModels.Chat.GPT4oMini\n override val defaultInspectorModel: LLModel = OpenAIModels.Chat.GPT4o\n override val envVar = \"OPENAI_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenAIModels.Chat.GPT4o,\n OpenAIModels.Chat.GPT4oMini,\n OpenAIModels.Chat.GPT4_1,\n OpenAIModels.Chat.GPT4_1Nano,\n OpenAIModels.Chat.GPT4_1Mini,\n OpenAIModels.Chat.O1,\n OpenAIModels.Chat.O3,\n OpenAIModels.Chat.O3Mini,\n OpenAIModels.Chat.O4Mini,\n OpenAIModels.Chat.GPT5,\n OpenAIModels.Chat.GPT5Mini,\n OpenAIModels.Chat.GPT5Nano,\n OpenAIModels.Chat.GPT5Codex,\n OpenAIModels.Chat.GPT5Pro,\n OpenAIModels.Chat.GPT5_1,\n OpenAIModels.Chat.GPT5_1Codex,\n OpenAIModels.Chat.GPT5_2,\n OpenAIModels.Chat.GPT5_2Pro,\n )\n\n override fun createClient(apiKey: String): OpenAILLMClient = OpenAILLMClient(apiKey)\n }\n\n object Google : VerityProvider() {\n override val name = \"google\"\n override val defaultNavigatorModel: LLModel = GoogleModels.Gemini2_0FlashLite\n override val defaultInspectorModel: LLModel = GoogleModels.Gemini2_5Pro\n override val envVar = \"GOOGLE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n GoogleModels.Gemini2_0Flash,\n GoogleModels.Gemini2_0Flash001,\n GoogleModels.Gemini2_0FlashLite,\n GoogleModels.Gemini2_0FlashLite001,\n GoogleModels.Gemini2_5Pro,\n GoogleModels.Gemini2_5Flash,\n GoogleModels.Gemini2_5FlashLite,\n GoogleModels.Gemini3_Pro_Preview,\n )\n\n override fun createClient(apiKey: String): GoogleLLMClient = GoogleLLMClient(apiKey)\n }\n\n object OpenRouter : VerityProvider() {\n override val name = \"openrouter\"\n override val defaultNavigatorModel: LLModel = OpenRouterModels.Phi4Reasoning\n override val defaultInspectorModel: LLModel = OpenRouterModels.Claude4_5Opus\n override val envVar = \"OPENROUTER_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenRouterModels.Phi4Reasoning,\n OpenRouterModels.Claude3Opus,\n OpenRouterModels.Claude3Sonnet,\n OpenRouterModels.Claude3Haiku,\n OpenRouterModels.Claude3_5Sonnet,\n OpenRouterModels.Claude3_7Sonnet,\n OpenRouterModels.Claude4Sonnet,\n OpenRouterModels.Claude4_1Opus,\n OpenRouterModels.Claude4_5Haiku,\n OpenRouterModels.Claude4_5Sonnet,\n OpenRouterModels.Claude4_5Opus,\n OpenRouterModels.Claude3VisionSonnet,\n OpenRouterModels.Claude3VisionOpus,\n OpenRouterModels.Claude3VisionHaiku,\n OpenRouterModels.GPT35Turbo,\n OpenRouterModels.GPT4,\n OpenRouterModels.GPT4o,\n OpenRouterModels.GPT4oMini,\n OpenRouterModels.GPT4Turbo,\n OpenRouterModels.GPT5,\n OpenRouterModels.GPT5Mini,\n OpenRouterModels.GPT5Nano,\n OpenRouterModels.GPT5Chat,\n OpenRouterModels.GPT_OSS_120b,\n OpenRouterModels.GPT5_2,\n OpenRouterModels.GPT5_2Pro,\n OpenRouterModels.Llama3,\n OpenRouterModels.Llama3Instruct,\n OpenRouterModels.Mistral7B,\n OpenRouterModels.Mixtral8x7B,\n OpenRouterModels.DeepSeekV30324,\n OpenRouterModels.Gemini2_5FlashLite,\n OpenRouterModels.Gemini2_5Flash,\n OpenRouterModels.Gemini2_5Pro,\n OpenRouterModels.Qwen2_5,\n OpenRouterModels.Qwen3VL,\n )\n\n override fun createClient(apiKey: String): OpenRouterLLMClient = OpenRouterLLMClient(apiKey)\n }\n\n object Bedrock : VerityProvider() {\n override val name = \"bedrock\"\n override val defaultNavigatorModel: LLModel = BedrockModels.AnthropicClaude4_5Haiku\n override val defaultInspectorModel: LLModel = BedrockModels.AnthropicClaude4_5Sonnet\n override val envVar = \"AWS_ACCESS_KEY_ID\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n BedrockModels.AnthropicClaude3Opus,\n BedrockModels.AnthropicClaude3Sonnet,\n BedrockModels.AnthropicClaude3Haiku,\n BedrockModels.AnthropicClaude4Opus,\n BedrockModels.AnthropicClaude41Opus,\n BedrockModels.AnthropicClaude45Opus,\n BedrockModels.AnthropicClaude4Sonnet,\n BedrockModels.AnthropicClaude4_5Sonnet,\n BedrockModels.AnthropicClaude4_5Haiku,\n BedrockModels.AnthropicClaude35SonnetV2,\n BedrockModels.AnthropicClaude35Haiku,\n BedrockModels.AnthropicClaude21,\n BedrockModels.AnthropicClaudeInstant,\n BedrockModels.AmazonNovaMicro,\n BedrockModels.AmazonNovaLite,\n BedrockModels.AmazonNovaPro,\n BedrockModels.AmazonNovaPremier,\n BedrockModels.AI21JambaLarge,\n BedrockModels.AI21JambaMini,\n BedrockModels.MetaLlama3_0_8BInstruct,\n BedrockModels.MetaLlama3_0_70BInstruct,\n BedrockModels.MetaLlama3_1_8BInstruct,\n BedrockModels.MetaLlama3_1_70BInstruct,\n BedrockModels.MetaLlama3_1_405BInstruct,\n BedrockModels.MetaLlama3_2_1BInstruct,\n BedrockModels.MetaLlama3_2_3BInstruct,\n BedrockModels.MetaLlama3_2_11BInstruct,\n BedrockModels.MetaLlama3_2_90BInstruct,\n BedrockModels.MetaLlama3_3_70BInstruct,\n )\n\n override fun createClient(apiKey: String): BedrockLLMClient = createClient(apiKey, System.getenv(\"AWS_SECRET_ACCESS_KEY\"))\n\n internal fun createClient(apiKey: String, awsSecretKey: String?): BedrockLLMClient {\n val secret = awsSecretKey\n ?: error(\"AWS_SECRET_ACCESS_KEY environment variable is required for the Bedrock provider\")\n val credProvider =\n StaticCredentialsProvider {\n accessKeyId = apiKey\n secretAccessKey = secret\n }\n return BedrockLLMClient(identityProvider = credProvider)\n }\n }\n\n object DeepSeek : VerityProvider() {\n override val name = \"deepseek\"\n override val defaultNavigatorModel: LLModel = DeepSeekModels.DeepSeekChat\n override val defaultInspectorModel: LLModel = DeepSeekModels.DeepSeekReasoner\n override val envVar = \"DEEPSEEK_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DeepSeekModels.DeepSeekChat,\n DeepSeekModels.DeepSeekReasoner,\n )\n\n override fun createClient(apiKey: String): DeepSeekLLMClient = DeepSeekLLMClient(apiKey)\n }\n\n object MistralAI : VerityProvider() {\n override val name = \"mistralai\"\n override val defaultNavigatorModel: LLModel = MistralAIModels.Chat.MistralSmall2\n override val defaultInspectorModel: LLModel = MistralAIModels.Chat.MagistralMedium12\n override val envVar = \"MISTRAL_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n MistralAIModels.Chat.MistralMedium31,\n MistralAIModels.Chat.MistralLarge21,\n MistralAIModels.Chat.MistralSmall2,\n MistralAIModels.Chat.MagistralMedium12,\n MistralAIModels.Chat.Codestral,\n MistralAIModels.Chat.DevstralMedium,\n )\n\n override fun createClient(apiKey: String): MistralAILLMClient = MistralAILLMClient(apiKey)\n }\n\n object Ollama : VerityProvider() {\n override val name = \"ollama\"\n override val defaultNavigatorModel: LLModel = OllamaModels.Meta.LLAMA_3_2_3B\n override val defaultInspectorModel: LLModel = OllamaModels.Meta.LLAMA_4_SCOUT\n override val envVar = \"OLLAMA_HOST\"\n override val requiresAuth = false\n\n override fun allModels(): List = listOf(\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_8B,\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_70B,\n OllamaModels.Meta.LLAMA_3_2_3B,\n OllamaModels.Meta.LLAMA_3_2,\n OllamaModels.Meta.LLAMA_4_SCOUT,\n OllamaModels.Meta.LLAMA_4,\n OllamaModels.Alibaba.QWEN_2_5_05B,\n OllamaModels.Alibaba.QWEN_3_06B,\n OllamaModels.Alibaba.QWQ_32B,\n OllamaModels.Alibaba.QWQ,\n OllamaModels.Alibaba.QWEN_CODER_2_5_32B,\n OllamaModels.Granite.GRANITE_3_2_VISION,\n )\n\n override fun createClient(apiKey: String): OllamaClient = OllamaClient(baseUrl = apiKey.ifBlank { \"http://localhost:11434\" })\n }\n\n object DashScope : VerityProvider() {\n override val name = \"dashscope\"\n override val defaultNavigatorModel: LLModel = DashscopeModels.QWEN_FLASH\n override val defaultInspectorModel: LLModel = DashscopeModels.QWEN3_MAX\n override val envVar = \"DASHSCOPE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DashscopeModels.QWEN_FLASH,\n DashscopeModels.QWEN3_OMNI_FLASH,\n DashscopeModels.QWEN_PLUS,\n DashscopeModels.QWEN_PLUS_LATEST,\n DashscopeModels.QWEN3_CODER_PLUS,\n DashscopeModels.QWEN3_CODER_FLASH,\n DashscopeModels.QWEN3_MAX,\n )\n\n override fun createClient(apiKey: String): DashscopeLLMClient = DashscopeLLMClient(apiKey)\n }\n\n companion object {\n /** All 9 supported providers. */\n val all: List =\n listOf(\n Anthropic,\n OpenAI,\n Google,\n OpenRouter,\n Bedrock,\n DeepSeek,\n MistralAI,\n Ollama,\n DashScope,\n )\n\n /** Looks up a provider by name, throws [IllegalStateException] for unknown names. */\n fun fromName(name: String): VerityProvider = all.find { it.name == name }\n ?: error(\n \"Unknown provider '$name'. Available providers: ${all.map { it.name }}\",\n )\n }\n}\n"}, "e8cfb342b9ebf2dbf3b2883082741163aabdba35": {"t": 1785755923.7926357, "n": 12723, "h": "b92eb241d6b3c9d3", "c": "package me.chrisbanes.verity.cli\n\nimport ai.koog.prompt.executor.clients.LLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicLLMClient\nimport ai.koog.prompt.executor.clients.anthropic.AnthropicModels\nimport ai.koog.prompt.executor.clients.bedrock.BedrockLLMClient\nimport ai.koog.prompt.executor.clients.bedrock.BedrockModels\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeLLMClient\nimport ai.koog.prompt.executor.clients.dashscope.DashscopeModels\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekLLMClient\nimport ai.koog.prompt.executor.clients.deepseek.DeepSeekModels\nimport ai.koog.prompt.executor.clients.google.GoogleLLMClient\nimport ai.koog.prompt.executor.clients.google.GoogleModels\nimport ai.koog.prompt.executor.clients.mistralai.MistralAILLMClient\nimport ai.koog.prompt.executor.clients.mistralai.MistralAIModels\nimport ai.koog.prompt.executor.clients.openai.OpenAILLMClient\nimport ai.koog.prompt.executor.clients.openai.OpenAIModels\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterLLMClient\nimport ai.koog.prompt.executor.clients.openrouter.OpenRouterModels\nimport ai.koog.prompt.executor.ollama.client.OllamaClient\nimport ai.koog.prompt.executor.ollama.client.OllamaModels\nimport ai.koog.prompt.llm.LLModel\nimport aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider\n\n/**\n * Represents a supported LLM provider for Verity.\n *\n * Each subclass specifies the provider's name, default models, authentication requirements,\n * and how to create the underlying Koog LLM client.\n */\nsealed class VerityProvider {\n /** CLI/config identifier for this provider. */\n abstract val name: String\n\n /** Cheap/fast model for YAML generation (navigator). */\n abstract val defaultNavigatorModel: LLModel\n\n /** Most capable model for assertion evaluation (inspector). */\n abstract val defaultInspectorModel: LLModel\n\n /** Environment variable name for the API key. */\n abstract val envVar: String\n\n /** Whether an API key is required to use this provider. False only for Ollama. */\n abstract val requiresAuth: Boolean\n\n /** All known chat models for this provider. */\n abstract fun allModels(): List\n\n /** Creates the Koog LLM client for this provider using the given API key (or host URL for Ollama). */\n abstract fun createClient(apiKey: String): LLMClient\n\n /** Looks up a model by its ID string, throws [IllegalStateException] if not found. */\n fun findModel(id: String): LLModel {\n val models = allModels()\n return models.find { it.id == id }\n ?: error(\"Unknown model '$id' for provider '$name'. Available: ${models.map { it.id }}\")\n }\n\n object Anthropic : VerityProvider() {\n override val name = \"anthropic\"\n override val defaultNavigatorModel: LLModel = AnthropicModels.Haiku_4_5\n override val defaultInspectorModel: LLModel = AnthropicModels.Opus_4_5\n override val envVar = \"ANTHROPIC_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n AnthropicModels.Opus_3,\n AnthropicModels.Haiku_3,\n AnthropicModels.Sonnet_3_5,\n AnthropicModels.Haiku_3_5,\n AnthropicModels.Sonnet_3_7,\n AnthropicModels.Sonnet_4,\n AnthropicModels.Opus_4,\n AnthropicModels.Opus_4_1,\n AnthropicModels.Opus_4_5,\n AnthropicModels.Sonnet_4_5,\n AnthropicModels.Haiku_4_5,\n )\n\n override fun createClient(apiKey: String): AnthropicLLMClient = AnthropicLLMClient(apiKey)\n }\n\n object OpenAI : VerityProvider() {\n override val name = \"openai\"\n override val defaultNavigatorModel: LLModel = OpenAIModels.Chat.GPT4oMini\n override val defaultInspectorModel: LLModel = OpenAIModels.Chat.GPT4o\n override val envVar = \"OPENAI_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenAIModels.Chat.GPT4o,\n OpenAIModels.Chat.GPT4oMini,\n OpenAIModels.Chat.GPT4_1,\n OpenAIModels.Chat.GPT4_1Nano,\n OpenAIModels.Chat.GPT4_1Mini,\n OpenAIModels.Chat.O1,\n OpenAIModels.Chat.O3,\n OpenAIModels.Chat.O3Mini,\n OpenAIModels.Chat.O4Mini,\n OpenAIModels.Chat.GPT5,\n OpenAIModels.Chat.GPT5Mini,\n OpenAIModels.Chat.GPT5Nano,\n OpenAIModels.Chat.GPT5Codex,\n OpenAIModels.Chat.GPT5Pro,\n OpenAIModels.Chat.GPT5_1,\n OpenAIModels.Chat.GPT5_1Codex,\n OpenAIModels.Chat.GPT5_2,\n OpenAIModels.Chat.GPT5_2Pro,\n )\n\n override fun createClient(apiKey: String): OpenAILLMClient = OpenAILLMClient(apiKey)\n }\n\n object Google : VerityProvider() {\n override val name = \"google\"\n override val defaultNavigatorModel: LLModel = GoogleModels.Gemini2_0FlashLite\n override val defaultInspectorModel: LLModel = GoogleModels.Gemini2_5Pro\n override val envVar = \"GOOGLE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n GoogleModels.Gemini2_0Flash,\n GoogleModels.Gemini2_0Flash001,\n GoogleModels.Gemini2_0FlashLite,\n GoogleModels.Gemini2_0FlashLite001,\n GoogleModels.Gemini2_5Pro,\n GoogleModels.Gemini2_5Flash,\n GoogleModels.Gemini2_5FlashLite,\n GoogleModels.Gemini3_Pro_Preview,\n )\n\n override fun createClient(apiKey: String): GoogleLLMClient = GoogleLLMClient(apiKey)\n }\n\n object OpenRouter : VerityProvider() {\n override val name = \"openrouter\"\n override val defaultNavigatorModel: LLModel = OpenRouterModels.Phi4Reasoning\n override val defaultInspectorModel: LLModel = OpenRouterModels.Claude4_5Opus\n override val envVar = \"OPENROUTER_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n OpenRouterModels.Phi4Reasoning,\n OpenRouterModels.Claude3Opus,\n OpenRouterModels.Claude3Sonnet,\n OpenRouterModels.Claude3Haiku,\n OpenRouterModels.Claude3_5Sonnet,\n OpenRouterModels.Claude3_7Sonnet,\n OpenRouterModels.Claude4Sonnet,\n OpenRouterModels.Claude4_1Opus,\n OpenRouterModels.Claude4_5Haiku,\n OpenRouterModels.Claude4_5Sonnet,\n OpenRouterModels.Claude4_5Opus,\n OpenRouterModels.Claude3VisionSonnet,\n OpenRouterModels.Claude3VisionOpus,\n OpenRouterModels.Claude3VisionHaiku,\n OpenRouterModels.GPT35Turbo,\n OpenRouterModels.GPT4,\n OpenRouterModels.GPT4o,\n OpenRouterModels.GPT4oMini,\n OpenRouterModels.GPT4Turbo,\n OpenRouterModels.GPT5,\n OpenRouterModels.GPT5Mini,\n OpenRouterModels.GPT5Nano,\n OpenRouterModels.GPT5Chat,\n OpenRouterModels.GPT_OSS_120b,\n OpenRouterModels.GPT5_2,\n OpenRouterModels.GPT5_2Pro,\n OpenRouterModels.Llama3,\n OpenRouterModels.Llama3Instruct,\n OpenRouterModels.Mistral7B,\n OpenRouterModels.Mixtral8x7B,\n OpenRouterModels.DeepSeekV30324,\n OpenRouterModels.Gemini2_5FlashLite,\n OpenRouterModels.Gemini2_5Flash,\n OpenRouterModels.Gemini2_5Pro,\n OpenRouterModels.Qwen2_5,\n OpenRouterModels.Qwen3VL,\n )\n\n override fun createClient(apiKey: String): OpenRouterLLMClient = OpenRouterLLMClient(apiKey)\n }\n\n object Bedrock : VerityProvider() {\n override val name = \"bedrock\"\n override val defaultNavigatorModel: LLModel = BedrockModels.AnthropicClaude4_5Haiku\n override val defaultInspectorModel: LLModel = BedrockModels.AnthropicClaude4_5Sonnet\n override val envVar = \"AWS_ACCESS_KEY_ID\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n BedrockModels.AnthropicClaude3Opus,\n BedrockModels.AnthropicClaude3Sonnet,\n BedrockModels.AnthropicClaude3Haiku,\n BedrockModels.AnthropicClaude4Opus,\n BedrockModels.AnthropicClaude41Opus,\n BedrockModels.AnthropicClaude45Opus,\n BedrockModels.AnthropicClaude4Sonnet,\n BedrockModels.AnthropicClaude4_5Sonnet,\n BedrockModels.AnthropicClaude4_5Haiku,\n BedrockModels.AnthropicClaude35SonnetV2,\n BedrockModels.AnthropicClaude35Haiku,\n BedrockModels.AnthropicClaude21,\n BedrockModels.AnthropicClaudeInstant,\n BedrockModels.AmazonNovaMicro,\n BedrockModels.AmazonNovaLite,\n BedrockModels.AmazonNovaPro,\n BedrockModels.AmazonNovaPremier,\n BedrockModels.AI21JambaLarge,\n BedrockModels.AI21JambaMini,\n BedrockModels.MetaLlama3_0_8BInstruct,\n BedrockModels.MetaLlama3_0_70BInstruct,\n BedrockModels.MetaLlama3_1_8BInstruct,\n BedrockModels.MetaLlama3_1_70BInstruct,\n BedrockModels.MetaLlama3_1_405BInstruct,\n BedrockModels.MetaLlama3_2_1BInstruct,\n BedrockModels.MetaLlama3_2_3BInstruct,\n BedrockModels.MetaLlama3_2_11BInstruct,\n BedrockModels.MetaLlama3_2_90BInstruct,\n BedrockModels.MetaLlama3_3_70BInstruct,\n )\n\n override fun createClient(apiKey: String): BedrockLLMClient {\n val secret = System.getenv(\"AWS_SECRET_ACCESS_KEY\")\n ?: error(\"AWS_SECRET_ACCESS_KEY environment variable is required for the Bedrock provider\")\n val credProvider =\n StaticCredentialsProvider {\n accessKeyId = apiKey\n secretAccessKey = secret\n }\n return BedrockLLMClient(identityProvider = credProvider)\n }\n }\n\n object DeepSeek : VerityProvider() {\n override val name = \"deepseek\"\n override val defaultNavigatorModel: LLModel = DeepSeekModels.DeepSeekChat\n override val defaultInspectorModel: LLModel = DeepSeekModels.DeepSeekReasoner\n override val envVar = \"DEEPSEEK_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DeepSeekModels.DeepSeekChat,\n DeepSeekModels.DeepSeekReasoner,\n )\n\n override fun createClient(apiKey: String): DeepSeekLLMClient = DeepSeekLLMClient(apiKey)\n }\n\n object MistralAI : VerityProvider() {\n override val name = \"mistralai\"\n override val defaultNavigatorModel: LLModel = MistralAIModels.Chat.MistralSmall2\n override val defaultInspectorModel: LLModel = MistralAIModels.Chat.MagistralMedium12\n override val envVar = \"MISTRAL_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n MistralAIModels.Chat.MistralMedium31,\n MistralAIModels.Chat.MistralLarge21,\n MistralAIModels.Chat.MistralSmall2,\n MistralAIModels.Chat.MagistralMedium12,\n MistralAIModels.Chat.Codestral,\n MistralAIModels.Chat.DevstralMedium,\n )\n\n override fun createClient(apiKey: String): MistralAILLMClient = MistralAILLMClient(apiKey)\n }\n\n object Ollama : VerityProvider() {\n override val name = \"ollama\"\n override val defaultNavigatorModel: LLModel = OllamaModels.Meta.LLAMA_3_2_3B\n override val defaultInspectorModel: LLModel = OllamaModels.Meta.LLAMA_4_SCOUT\n override val envVar = \"OLLAMA_HOST\"\n override val requiresAuth = false\n\n override fun allModels(): List = listOf(\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_8B,\n OllamaModels.Groq.LLAMA_3_GROK_TOOL_USE_70B,\n OllamaModels.Meta.LLAMA_3_2_3B,\n OllamaModels.Meta.LLAMA_3_2,\n OllamaModels.Meta.LLAMA_4_SCOUT,\n OllamaModels.Meta.LLAMA_4,\n OllamaModels.Alibaba.QWEN_2_5_05B,\n OllamaModels.Alibaba.QWEN_3_06B,\n OllamaModels.Alibaba.QWQ_32B,\n OllamaModels.Alibaba.QWQ,\n OllamaModels.Alibaba.QWEN_CODER_2_5_32B,\n OllamaModels.Granite.GRANITE_3_2_VISION,\n )\n\n override fun createClient(apiKey: String): OllamaClient = OllamaClient(baseUrl = apiKey.ifBlank { \"http://localhost:11434\" })\n }\n\n object DashScope : VerityProvider() {\n override val name = \"dashscope\"\n override val defaultNavigatorModel: LLModel = DashscopeModels.QWEN_FLASH\n override val defaultInspectorModel: LLModel = DashscopeModels.QWEN3_MAX\n override val envVar = \"DASHSCOPE_API_KEY\"\n override val requiresAuth = true\n\n override fun allModels(): List = listOf(\n DashscopeModels.QWEN_FLASH,\n DashscopeModels.QWEN3_OMNI_FLASH,\n DashscopeModels.QWEN_PLUS,\n DashscopeModels.QWEN_PLUS_LATEST,\n DashscopeModels.QWEN3_CODER_PLUS,\n DashscopeModels.QWEN3_CODER_FLASH,\n DashscopeModels.QWEN3_MAX,\n )\n\n override fun createClient(apiKey: String): DashscopeLLMClient = DashscopeLLMClient(apiKey)\n }\n\n companion object {\n /** All 9 supported providers. */\n val all: List =\n listOf(\n Anthropic,\n OpenAI,\n Google,\n OpenRouter,\n Bedrock,\n DeepSeek,\n MistralAI,\n Ollama,\n DashScope,\n )\n\n /** Looks up a provider by name, throws [IllegalStateException] for unknown names. */\n fun fromName(name: String): VerityProvider = all.find { it.name == name }\n ?: error(\n \"Unknown provider '$name'. Available providers: ${all.map { it.name }}\",\n )\n }\n}\n"}}, "verity/docs/plans/2026-03-13-multi-provider-design.md": {"0e61eda0d58e0cc6301d198d5efd23bd2e32b765": {"t": 1785747216.4708536, "n": 4197, "h": "55c5b9c8e9c42a9d", "c": "# Multi-Provider LLM Support — Design\n\n## Goal\n\nReplace the hardcoded Anthropic provider in the CLI with a provider registry that supports all 9 Koog-backed LLM providers. Users select their provider and models via a config file (`verity/config.yaml`) or CLI flags.\n\n## Provider Registry\n\nA `VerityProvider` sealed class in `:verity:cli` maps each Koog provider to its defaults:\n\n```kotlin\nsealed class VerityProvider(\n val name: String,\n val defaultNavigatorModel: LLModel,\n val defaultInspectorModel: LLModel,\n val envVar: String,\n) {\n abstract fun createClient(apiKey: String): LLMClient\n}\n```\n\n### Supported Providers\n\n| Provider | Name | Navigator (cheap) | Inspector (capable) | Env Var | Vision |\n|----------|------|-------------------|---------------------|---------|--------|\n| Anthropic | `anthropic` | `Haiku_4_5` | `Opus_4_5` | `ANTHROPIC_API_KEY` | Yes |\n| OpenAI | `openai` | `GPT4oMini` | `GPT4o` | `OPENAI_API_KEY` | Yes |\n| Google | `google` | `Gemini2_0FlashLite` | `Gemini2_5Pro` | `GOOGLE_API_KEY` | Yes |\n| OpenRouter | `openrouter` | `Phi4Reasoning` | `Claude4_5Opus` | `OPENROUTER_API_KEY` | Yes |\n| Bedrock | `bedrock` | `Claude3Haiku` | `Claude3Opus` | `AWS_ACCESS_KEY_ID` | Yes |\n| DeepSeek | `deepseek` | `DeepSeekChat` | `DeepSeekReasoner` | `DEEPSEEK_API_KEY` | No |\n| Mistral AI | `mistralai` | `MistralSmall2` | `MagistralMedium12` | `MISTRAL_API_KEY` | Yes |\n| Ollama | `ollama` | `LLAMA_3_2_3B` | `LLAMA_4_SCOUT` | None | Limited |\n| DashScope | `dashscope` | `QWEN_FLASH` | `QWEN3_OMNI_FLASH` | `DASHSCOPE_API_KEY` | Yes |\n\n### Special Cases\n\n- **Bedrock**: Uses AWS credentials (`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`) instead of a single API key.\n- **Ollama**: No API key required. Reads `OLLAMA_HOST` env var (or `--api-key` as host URL), defaulting to `http://localhost:11434`.\n- **DeepSeek**: No vision support. Visual assertions fall back to tree-only evaluation.\n\n## Config File\n\nLocation: `verity/config.yaml` in project root. Parsed with Kaml.\n\n```yaml\nprovider: anthropic\nnavigator-model: claude-haiku-4-5\ninspector-model: claude-sonnet-4-5\n```\n\nAll fields optional. Missing file defaults to Anthropic with provider defaults.\n\n```kotlin\n@Serializable\ndata class VerityConfig(\n val provider: String? = null,\n @SerialName(\"navigator-model\") val navigatorModel: String? = null,\n @SerialName(\"inspector-model\") val inspectorModel: String? = null,\n)\n```\n\n## CLI Flags\n\nNew shared options on the root `Verity` command:\n\n```\n--provider LLM provider (default: from config or anthropic)\n--navigator-model Override navigator model ID\n--inspector-model Override inspector model ID\n```\n\nExisting `--api-key` flag remains. Its `envvar` becomes dynamic based on the resolved provider.\n\n## Resolution Priority\n\n**CLI flags > config file > provider defaults**\n\n1. Load config from `verity/config.yaml` (if exists).\n2. Resolve provider: CLI `--provider` > config `provider` > `anthropic`.\n3. Resolve API key: CLI `--api-key` > provider's env var.\n4. Resolve models: CLI `--navigator-model` > config `navigator-model` > provider default.\n5. Create executor via `provider.createClient(apiKey)` wrapped in `SingleLLMPromptExecutor`.\n6. Look up `LLModel` objects by string ID from the provider's model list.\n\n## RunCommand Changes\n\nRunCommand becomes thin — resolves the provider, models, and API key, then delegates to Orchestrator the same as today but with resolved values instead of hardcoded ones.\n\n## Dependencies\n\nNew entries in `libs.versions.toml` for all 8 additional Koog provider artifacts (`koog-anthropic` already exists). All added to `:verity:cli` only — agent/core/device/mcp modules stay untouched.\n\n## Testing\n\n- Provider registry: each provider resolves correct client type and default models.\n- `findModel(id)`: returns correct `LLModel` for a string ID.\n- Config loading: missing file, partial config, full config.\n- Resolution priority: CLI flags override config, config overrides defaults.\n- No integration tests calling real LLM APIs.\n\n## Scope\n\n- Only the `:verity:cli` module changes.\n- The agent module's provider-agnostic architecture (caller-owned Koog factories) is the foundation that makes this work.\n"}, "e8cfb342b9ebf2dbf3b2883082741163aabdba35": {"t": 1785755919.3979077, "n": 4197, "h": "55c5b9c8e9c42a9d", "c": "# Multi-Provider LLM Support — Design\n\n## Goal\n\nReplace the hardcoded Anthropic provider in the CLI with a provider registry that supports all 9 Koog-backed LLM providers. Users select their provider and models via a config file (`verity/config.yaml`) or CLI flags.\n\n## Provider Registry\n\nA `VerityProvider` sealed class in `:verity:cli` maps each Koog provider to its defaults:\n\n```kotlin\nsealed class VerityProvider(\n val name: String,\n val defaultNavigatorModel: LLModel,\n val defaultInspectorModel: LLModel,\n val envVar: String,\n) {\n abstract fun createClient(apiKey: String): LLMClient\n}\n```\n\n### Supported Providers\n\n| Provider | Name | Navigator (cheap) | Inspector (capable) | Env Var | Vision |\n|----------|------|-------------------|---------------------|---------|--------|\n| Anthropic | `anthropic` | `Haiku_4_5` | `Opus_4_5` | `ANTHROPIC_API_KEY` | Yes |\n| OpenAI | `openai` | `GPT4oMini` | `GPT4o` | `OPENAI_API_KEY` | Yes |\n| Google | `google` | `Gemini2_0FlashLite` | `Gemini2_5Pro` | `GOOGLE_API_KEY` | Yes |\n| OpenRouter | `openrouter` | `Phi4Reasoning` | `Claude4_5Opus` | `OPENROUTER_API_KEY` | Yes |\n| Bedrock | `bedrock` | `Claude3Haiku` | `Claude3Opus` | `AWS_ACCESS_KEY_ID` | Yes |\n| DeepSeek | `deepseek` | `DeepSeekChat` | `DeepSeekReasoner` | `DEEPSEEK_API_KEY` | No |\n| Mistral AI | `mistralai` | `MistralSmall2` | `MagistralMedium12` | `MISTRAL_API_KEY` | Yes |\n| Ollama | `ollama` | `LLAMA_3_2_3B` | `LLAMA_4_SCOUT` | None | Limited |\n| DashScope | `dashscope` | `QWEN_FLASH` | `QWEN3_OMNI_FLASH` | `DASHSCOPE_API_KEY` | Yes |\n\n### Special Cases\n\n- **Bedrock**: Uses AWS credentials (`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`) instead of a single API key.\n- **Ollama**: No API key required. Reads `OLLAMA_HOST` env var (or `--api-key` as host URL), defaulting to `http://localhost:11434`.\n- **DeepSeek**: No vision support. Visual assertions fall back to tree-only evaluation.\n\n## Config File\n\nLocation: `verity/config.yaml` in project root. Parsed with Kaml.\n\n```yaml\nprovider: anthropic\nnavigator-model: claude-haiku-4-5\ninspector-model: claude-sonnet-4-5\n```\n\nAll fields optional. Missing file defaults to Anthropic with provider defaults.\n\n```kotlin\n@Serializable\ndata class VerityConfig(\n val provider: String? = null,\n @SerialName(\"navigator-model\") val navigatorModel: String? = null,\n @SerialName(\"inspector-model\") val inspectorModel: String? = null,\n)\n```\n\n## CLI Flags\n\nNew shared options on the root `Verity` command:\n\n```\n--provider LLM provider (default: from config or anthropic)\n--navigator-model Override navigator model ID\n--inspector-model Override inspector model ID\n```\n\nExisting `--api-key` flag remains. Its `envvar` becomes dynamic based on the resolved provider.\n\n## Resolution Priority\n\n**CLI flags > config file > provider defaults**\n\n1. Load config from `verity/config.yaml` (if exists).\n2. Resolve provider: CLI `--provider` > config `provider` > `anthropic`.\n3. Resolve API key: CLI `--api-key` > provider's env var.\n4. Resolve models: CLI `--navigator-model` > config `navigator-model` > provider default.\n5. Create executor via `provider.createClient(apiKey)` wrapped in `SingleLLMPromptExecutor`.\n6. Look up `LLModel` objects by string ID from the provider's model list.\n\n## RunCommand Changes\n\nRunCommand becomes thin — resolves the provider, models, and API key, then delegates to Orchestrator the same as today but with resolved values instead of hardcoded ones.\n\n## Dependencies\n\nNew entries in `libs.versions.toml` for all 8 additional Koog provider artifacts (`koog-anthropic` already exists). All added to `:verity:cli` only — agent/core/device/mcp modules stay untouched.\n\n## Testing\n\n- Provider registry: each provider resolves correct client type and default models.\n- `findModel(id)`: returns correct `LLModel` for a string ID.\n- Config loading: missing file, partial config, full config.\n- Resolution priority: CLI flags override config, config overrides defaults.\n- No integration tests calling real LLM APIs.\n\n## Scope\n\n- Only the `:verity:cli` module changes.\n- The agent module's provider-agnostic architecture (caller-owned Koog factories) is the foundation that makes this work.\n"}}}}