-
Notifications
You must be signed in to change notification settings - Fork 82
feat: add Atlas Cloud provider #229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { describe, expect, test } from 'bun:test'; | ||
|
|
||
| import { | ||
| CURATED_MODELS, | ||
| PROVIDER_INFO, | ||
| PROVIDER_MODEL_DOCS, | ||
| PROVIDER_SETUP_LINKS | ||
| } from './constants.ts'; | ||
|
|
||
| describe('Atlas Cloud connect metadata', () => { | ||
| test('provides authenticated setup and a default model', () => { | ||
| expect(PROVIDER_INFO.atlascloud).toEqual({ label: 'Atlas Cloud', requiresAuth: true }); | ||
| expect(CURATED_MODELS.atlascloud).toContainEqual({ | ||
| id: 'deepseek-ai/deepseek-v4-pro', | ||
| label: 'DeepSeek V4 Pro' | ||
| }); | ||
| expect(PROVIDER_SETUP_LINKS.atlascloud?.url).toBe('https://www.atlascloud.ai/console/api-keys'); | ||
| expect(PROVIDER_MODEL_DOCS.atlascloud?.url).toBe('https://api.atlascloud.ai/api/v1/models'); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { afterEach, describe, expect, test } from 'bun:test'; | ||
|
|
||
| import { getAuthStatus, getProviderAuthHint } from './auth.ts'; | ||
| import { ATLAS_CLOUD_BASE_URL, createAtlasCloud } from './atlascloud.ts'; | ||
| import { getProviderFactory, isProviderSupported } from './registry.ts'; | ||
|
|
||
| describe('Atlas Cloud provider', () => { | ||
| afterEach(() => { | ||
| delete process.env.ATLASCLOUD_API_KEY; | ||
| }); | ||
|
|
||
| test('registers an OpenAI-compatible chat model', () => { | ||
| const factory = getProviderFactory('atlascloud'); | ||
| expect(isProviderSupported('atlascloud')).toBe(true); | ||
| expect(factory).toBeDefined(); | ||
|
|
||
| const model = createAtlasCloud({ apiKey: 'test-key' })('deepseek-ai/deepseek-v4-pro'); | ||
| expect(model.provider).toBe('atlascloud.chat'); | ||
| expect(model.modelId).toBe('deepseek-ai/deepseek-v4-pro'); | ||
| expect(ATLAS_CLOUD_BASE_URL).toBe('https://api.atlascloud.ai/v1'); | ||
| }); | ||
|
|
||
| test('reads ATLASCLOUD_API_KEY for authentication', async () => { | ||
| process.env.ATLASCLOUD_API_KEY = 'test-atlas-key'; | ||
|
|
||
| expect(await getAuthStatus('atlascloud')).toEqual({ | ||
| status: 'ok', | ||
| authType: 'api', | ||
| apiKey: 'test-atlas-key' | ||
| }); | ||
| expect(getProviderAuthHint('atlascloud')).toContain('ATLASCLOUD_API_KEY'); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; | ||
|
|
||
| export const ATLAS_CLOUD_BASE_URL = 'https://api.atlascloud.ai/v1'; | ||
|
|
||
| const readEnv = (key: string) => { | ||
| const value = process.env[key]; | ||
| return value && value.trim().length > 0 ? value.trim() : undefined; | ||
| }; | ||
|
|
||
| export function createAtlasCloud( | ||
| options: { | ||
| apiKey?: string; | ||
| baseURL?: string; | ||
| headers?: Record<string, string>; | ||
| name?: string; | ||
| } = {} | ||
| ) { | ||
| const provider = createOpenAICompatible({ | ||
| name: options.name ?? 'atlascloud', | ||
| apiKey: options.apiKey ?? readEnv('ATLASCLOUD_API_KEY'), | ||
| baseURL: options.baseURL ?? readEnv('ATLASCLOUD_BASE_URL') ?? ATLAS_CLOUD_BASE_URL, | ||
| headers: options.headers | ||
| }); | ||
|
|
||
| return (modelId: string) => provider.chatModel(modelId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ export type AuthStatus = | |
| | { status: 'invalid'; authType: AuthType }; | ||
|
|
||
| const PROVIDER_AUTH_TYPES: Record<string, readonly AuthType[]> = { | ||
| atlascloud: ['api'], | ||
| opencode: ['api'], | ||
| 'github-copilot': ['oauth'], | ||
| openrouter: ['api'], | ||
|
|
@@ -35,6 +36,7 @@ const readEnv = (key: string) => { | |
| }; | ||
|
|
||
| const getEnvApiKey = (providerId: string) => { | ||
| if (providerId === 'atlascloud') return readEnv('ATLASCLOUD_API_KEY'); | ||
| if (providerId === 'openrouter') return readEnv('OPENROUTER_API_KEY'); | ||
| if (providerId === 'opencode') return readEnv('OPENCODE_API_KEY'); | ||
| if (providerId === 'minimax') return readEnv('MINIMAX_API_KEY'); | ||
|
|
@@ -141,6 +143,8 @@ export const getAuthStatus = async (providerId: string): Promise<AuthStatus> => | |
|
|
||
| export const getProviderAuthHint = (providerId: string) => { | ||
| switch (providerId) { | ||
| case 'atlascloud': | ||
| return 'Set ATLASCLOUD_API_KEY or run "btca connect -p atlascloud".'; | ||
|
Comment on lines
+146
to
+147
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Make the provider-only authentication command effective. The hint advertises 🤖 Prompt for AI Agents |
||
| case 'github-copilot': | ||
| return 'Run "btca connect -p github-copilot" and complete device flow OAuth.'; | ||
| case 'openai': | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Restore the previous environment value after the test.
afterEachalways deletesprocess.env.ATLASCLOUD_API_KEY. If the test process already contains this variable, later tests lose shared state. Capture the previous value and restore it after each test.🤖 Prompt for AI Agents