Add Anthropic as alternative AI text provider#159
Merged
Conversation
Introduce provider factory pattern for AI text and image providers, replacing hardcoded OpenAI imports in CLI commands. Users can now set `ai.provider: 'anthropic'` in config to use Claude models. Closes #107 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #159 +/- ##
==========================================
+ Coverage 64.65% 67.44% +2.78%
==========================================
Files 57 58 +1
Lines 2340 2543 +203
Branches 369 429 +60
==========================================
+ Hits 1513 1715 +202
- Misses 827 828 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Contributor
There was a problem hiding this comment.
Pull request overview
Adds Anthropic (Claude) as an alternative text AI provider, wiring provider selection through config/schema and centralizing CLI provider creation so commands can route to either OpenAI or Anthropic.
Changes:
- Introduce
AIProvider('openai' | 'anthropic') and update config schema +config initwizard to support Anthropic. - Add
createAnthropicTextProviderand CLI provider factories (createTextAIProvider,createImageProvider,getApiKeyForProvider) and update CLI commands to use them. - Add Anthropic SDK dependency and update docs +
.env.exampleforANTHROPIC_API_KEY.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/providers/ai/anthropicTextProvider.test.ts | Adds unit tests for Anthropic text provider behavior and error cases. |
| tests/cli/shared/providers.test.ts | Adds tests for provider factory routing and env-key lookup. |
| src/providers/ai/anthropicTextProvider.ts | Implements Anthropic-based TextAIProvider. |
| src/core/types.ts | Adds AIProvider union type. |
| src/core/config.ts | Updates config typing and Zod schema to allow anthropic. |
| src/cli/shared/providers.ts | Centralizes provider/env-key mapping and provider factory creation. |
| src/cli/commands/seo.ts | Uses provider factory instead of hardcoded OpenAI provider. |
| src/cli/commands/review.ts | Uses provider factory and updates missing-key messaging. |
| src/cli/commands/prepare.ts | Uses provider factories for text + image providers. |
| src/cli/commands/fix.ts | Uses provider factory instead of hardcoded OpenAI provider. |
| src/cli/commands/cover.ts | Uses provider factories for text + image providers. |
| src/cli/commands/configInit.ts | Adds Anthropic option and prints correct env next steps. |
| src/cli/commands/analyze.ts | Uses provider factory instead of conditional OpenAI usage. |
| package.json | Adds @anthropic-ai/sdk dependency. |
| package-lock.json | Locks Anthropic SDK and transitive dependencies. |
| docs/providers.md | Documents Anthropic setup and clarifies image generation remains OpenAI-only. |
| docs/environment-variables.md | Documents ANTHROPIC_API_KEY and updated command/key behavior. |
| .env.example | Adds ANTHROPIC_API_KEY placeholder. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+33
to
+35
| const content = textBlock.text; | ||
| const jsonMatch = content.match(/\{[\s\S]*\}/); | ||
| if (!jsonMatch) { |
| ); | ||
| } | ||
|
|
||
| return JSON.parse(jsonMatch[0]) as TOutput; |
…centralized key names - cover/prepare: error immediately when --generate requested but OPENAI_API_KEY missing, instead of silently skipping - anthropicTextProvider: prefer fenced code blocks for JSON extraction, use balanced-brace parser instead of greedy regex, wrap JSON.parse in try/catch to throw KtaviError with cause - review/cover: use getApiKeyEnvName() instead of inline provider check - Add 5 new tests (code block extraction, balanced parse, malformed JSON, getApiKeyEnvName) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment on lines
+5
to
+13
| const start = text.indexOf('{'); | ||
| if (start === -1) return null; | ||
|
|
||
| let depth = 0; | ||
| for (let i = start; i < text.length; i++) { | ||
| if (text[i] === '{') depth++; | ||
| else if (text[i] === '}') depth--; | ||
| if (depth === 0) return text.slice(start, i + 1); | ||
| } |
Introduce KTAVI_TEXT_API_KEY for text generation and KTAVI_IMAGE_API_KEY for image generation, with provider-specific keys (OPENAI_API_KEY, ANTHROPIC_API_KEY) as fallbacks. Switching providers is now purely a config change — .env stays the same. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…onses
extractJsonObject now tries each `{` candidate until JSON.parse succeeds,
handling cases where the model uses braces in explanatory text before the
actual JSON payload. Also improves error message clarity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| if (!apiKey) { | ||
| throw new KtaviError( | ||
| 'OPENAI_API_KEY is not set. Please add it to your .env file.', | ||
| 'API key is not set. Please set KTAVI_IMAGE_API_KEY in your .env file.', |
| if (!apiKey) { | ||
| throw new KtaviError( | ||
| 'OPENAI_API_KEY is not set. Please add it to your .env file.', | ||
| 'API key is not set. Please set KTAVI_TEXT_API_KEY in your .env file.', |
| imageProvider = createImageProvider(config, process.env); | ||
| if (!imageProvider) { | ||
| logger.error( | ||
| 'KTAVI_IMAGE_API_KEY is required for image generation. Add it to your .env file.', |
| export function createAnthropicTextProvider(apiKey: string, model: string): TextAIProvider { | ||
| if (!apiKey) { | ||
| throw new KtaviError( | ||
| 'API key is not set. Please set KTAVI_TEXT_API_KEY in your .env file.', |
… vars
- Make extractJsonObject track string context so braces inside JSON
string values (e.g. {"text": "}"}) don't break depth counting
- Update all provider and CLI error messages to mention both the KTAVI
key and the provider-specific fallback key
- Fix integration test asserting old error text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment on lines
+197
to
+199
| steps.push( | ||
| 'Set KTAVI_TEXT_API_KEY in your .env (or the provider-specific key like OPENAI_API_KEY)', | ||
| ); |
Comment on lines
+20
to
+25
| **Image model** is used by: `cover --generate` and `prepare --generate-cover`. Image generation currently uses OpenAI regardless of the text provider setting. | ||
|
|
||
| Set your API key in `.env`: | ||
|
|
||
| ``` | ||
| OPENAI_API_KEY=sk-... | ||
| KTAVI_TEXT_API_KEY=sk-... |
Comment on lines
7
to
+11
|
|
||
| describe('openaiImageProvider', () => { | ||
| it('throws KtaviError when API key is empty', () => { | ||
| expect(() => createOpenAIImageProvider('')).toThrow(KtaviError); | ||
| expect(() => createOpenAIImageProvider('')).toThrow('OPENAI_API_KEY is not set'); | ||
| expect(() => createOpenAIImageProvider('')).toThrow('KTAVI_IMAGE_API_KEY'); |
…or messages - Default textModel to claude-sonnet-4 when provider is anthropic (deepMerge applies provider-specific default when textModel is not explicitly set in the user config) - Config init wizard now suggests the correct model for the selected provider and tailors next-steps to mention the right fallback key - Document KTAVI_IMAGE_API_KEY in providers.md - Integration test reads KTAVI_IMAGE_API_KEY with OPENAI_API_KEY fallback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
anthropicas a supportedai.provideroption alongsideopenaicreateTextAIProvider,createImageProvider) insrc/cli/shared/providers.ts, replacing hardcoded OpenAI imports in all 6 CLI commands@anthropic-ai/sdkdependency andsrc/providers/ai/anthropicTextProvider.tsimplementationAIProvidertype ('openai' | 'anthropic') to core typesz.enum(['openai', 'anthropic'])config initwizard with Anthropic choiceproviders.md,environment-variables.md) and.env.exampleUsage
Image generation still requires
OPENAI_API_KEYsince Anthropic doesn't offer image generation.Closes #107
Test plan
🤖 Generated with Claude Code