diff --git a/AGENTS.md b/AGENTS.md index 1e917d7..2169730 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,7 +83,7 @@ Coding Guidelines - Testability: keep parsers and small helpers pure; avoid `Process()`/AppKit in ViewModel. - Provider Icon Theme Handling: - Use `ProviderIconThemeHelper` (in `utils/ProviderIconThemeHelper.swift`) for consistent dark/light mode icon adaptation. - - Icons that are black or dark-colored (ChatGPTIcon/Codex, KimiIcon, ZaiIcon, OpenRouterIcon) must be inverted in dark mode for visibility. + - Icons that are black or dark-colored (ChatGPTIcon/Codex, KimiIcon, ZaiIcon, OpenRouterIcon, RequestyIcon) must be inverted in dark mode for visibility. - For SwiftUI views: use `.providerIconTheme(iconName:)` modifier or `ProviderIconDarkModeModifier` directly. - For AppKit menus: use `ProviderIconThemeHelper.menuImage(named:)` which automatically handles resizing and dark mode inversion. - Do NOT manually check dark mode and invert icons; always use the helper to ensure consistency across the app. diff --git a/assets/Assets.xcassets/RequestyIcon.imageset/Contents.json b/assets/Assets.xcassets/RequestyIcon.imageset/Contents.json new file mode 100644 index 0000000..a5c1099 --- /dev/null +++ b/assets/Assets.xcassets/RequestyIcon.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "requesty.svg", + "idiom" : "mac" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "original" + } +} diff --git a/assets/Assets.xcassets/RequestyIcon.imageset/requesty.svg b/assets/Assets.xcassets/RequestyIcon.imageset/requesty.svg new file mode 100644 index 0000000..997639c --- /dev/null +++ b/assets/Assets.xcassets/RequestyIcon.imageset/requesty.svg @@ -0,0 +1 @@ +Requesty diff --git a/payload/providers.json b/payload/providers.json index 798f1fe..11a26ab 100644 --- a/payload/providers.json +++ b/payload/providers.json @@ -48,6 +48,49 @@ } } }, + { + "id" : "requesty", + "name" : "Requesty", + "class" : "openai-compatible", + "managedByCodMate" : true, + "envKey" : "REQUESTY_API_KEY", + "keyURL" : "https://app.requesty.ai/api-keys", + "docsURL" : "https://docs.requesty.ai", + "connectors" : { + "codex" : { + "baseURL" : "https://router.requesty.ai/v1", + "wireAPI" : "chat", + "envHttpHeaders" : { + "HTTP-Referer" : "REQUESTY_REFERRER", + "X-Title" : "REQUESTY_TITLE" + } + }, + "claudeCode" : { + "baseURL" : "https://router.requesty.ai", + "modelAliases" : { + "default" : "anthropic/claude-sonnet-4-5" + }, + "envHttpHeaders" : { + "x-api-key" : "REQUESTY_API_KEY", + "HTTP-Referer" : "REQUESTY_REFERRER", + "X-Title" : "REQUESTY_TITLE" + } + } + }, + "catalog" : { + "models" : [ + { "vendorModelId" : "openai/gpt-4o-mini", "caps" : { "reasoning": false, "tool_use": true, "long_context": true, "vision": true } }, + { "vendorModelId" : "anthropic/claude-sonnet-4-5", "caps" : { "reasoning": true, "tool_use": true, "long_context": true, "vision": true } }, + { "vendorModelId" : "google/gemini-2.5-flash", "caps" : { "reasoning": true, "tool_use": true, "long_context": true, "vision": true } } + ] + }, + "recommended" : { + "defaultModelFor" : { + "codex" : "openai/gpt-4o-mini", + "claudeCode" : "anthropic/claude-sonnet-4-5" + } + } + }, { "id" : "openai", "name" : "OpenAI", diff --git a/utils/ProviderIconResource.swift b/utils/ProviderIconResource.swift index 585aa0b..dc8e8a2 100644 --- a/utils/ProviderIconResource.swift +++ b/utils/ProviderIconResource.swift @@ -33,6 +33,8 @@ enum ProviderIconResource { IconMetadata( name: "OpenRouterIcon", requiresDarkModeInversion: true, aliases: ["openrouter", "open-router"]), + IconMetadata( + name: "RequestyIcon", requiresDarkModeInversion: true, aliases: ["requesty"]), IconMetadata( name: "ZaiIcon", requiresDarkModeInversion: true, aliases: ["zai", "z.ai", "glm"]), IconMetadata( @@ -82,6 +84,8 @@ enum ProviderIconResource { return "MiniMaxIcon" } else if baseURL.contains("openrouter.ai") { return "OpenRouterIcon" + } else if baseURL.contains("requesty.ai") { + return "RequestyIcon" } else if baseURL.contains("zai.com") || baseURL.contains("z.ai") || baseURL.contains("bigmodel.cn") { diff --git a/views/ProvidersSettingsView.swift b/views/ProvidersSettingsView.swift index 9df06c5..8e7d3a7 100644 --- a/views/ProvidersSettingsView.swift +++ b/views/ProvidersSettingsView.swift @@ -1384,7 +1384,7 @@ private struct ProviderEditorSheet: View { VStack(alignment: .leading, spacing: 12) { Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 12) { // Icon picker (only for user-created providers, not bundled/preset providers) - // Bundled providers (Anthropic, DeepSeek, GLM, K2, MiniMax, OpenAI, OpenRouter) use preset brand icons + // Bundled providers (Anthropic, DeepSeek, GLM, K2, MiniMax, OpenAI, OpenRouter, Requesty) use preset brand icons if vm.isNewProvider || (!vm.isEditingBundledProvider() && vm.editingProviderBinding()?.managedByCodMate == true)