-
Notifications
You must be signed in to change notification settings - Fork 2.8k
add support for custom anthropic models #16673
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: master
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 | ||||
|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||
| // ***************************************************************************** | ||||||
| // Copyright (C) 2024 EclipseSource GmbH. | ||||||
| // Copyright (C) 2024, 2025 EclipseSource GmbH. | ||||||
| // | ||||||
| // This program and the accompanying materials are made available under the | ||||||
| // terms of the Eclipse Public License v. 2.0 which is available at | ||||||
|
|
@@ -19,6 +19,7 @@ import { nls, PreferenceSchema } from '@theia/core'; | |||||
|
|
||||||
| export const API_KEY_PREF = 'ai-features.anthropic.AnthropicApiKey'; | ||||||
| export const MODELS_PREF = 'ai-features.anthropic.AnthropicModels'; | ||||||
| export const CUSTOM_ENDPOINTS_PREF = 'ai-features.AnthropicCustom.customAnthropicModels'; | ||||||
|
Member
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.
Suggested change
|
||||||
|
|
||||||
| export const AnthropicPreferencesSchema: PreferenceSchema = { | ||||||
| properties: { | ||||||
|
|
@@ -38,5 +39,61 @@ export const AnthropicPreferencesSchema: PreferenceSchema = { | |||||
| type: 'string' | ||||||
| } | ||||||
| }, | ||||||
| [CUSTOM_ENDPOINTS_PREF]: { | ||||||
| type: 'array', | ||||||
| title: AI_CORE_PREFERENCES_TITLE, | ||||||
| markdownDescription: nls.localize('theia/ai/anthropic/useResponseApi/mdDescription', | ||||||
|
Member
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.
Suggested change
|
||||||
| 'Integrate custom models compatible with the Anthropic API. The required attributes are `model` and `url`.\ | ||||||
| \n\ | ||||||
| Optionally, you can\ | ||||||
| \n\ | ||||||
| - specify a unique `id` to identify the custom model in the UI. If none is given `model` will be used as `id`.\ | ||||||
| \n\ | ||||||
| - provide an `apiKey` to access the API served at the given url. Use `true` to indicate the use of the global anthropic API key.\ | ||||||
| \n\ | ||||||
| - specify `enableStreaming: false` to indicate that streaming shall not be used.\ | ||||||
| \n\ | ||||||
| - specify `useCaching: false` to indicate that prompt caching shall not be used.\ | ||||||
| \n\ | ||||||
| - specify `maxRetries: <number>` to indicate the maximum number of retries when a request fails. 3 by default.'), | ||||||
| default: [], | ||||||
| items: { | ||||||
| type: 'object', | ||||||
| properties: { | ||||||
| model: { | ||||||
| type: 'string', | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/modelId/title', 'Model ID') | ||||||
| }, | ||||||
| url: { | ||||||
| type: 'string', | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/url/title', 'The Anthropic API compatible endpoint where the model is hosted') | ||||||
| }, | ||||||
| id: { | ||||||
| type: 'string', | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/id/title', 'A unique identifier which is used in the UI to identify the custom model'), | ||||||
| }, | ||||||
| apiKey: { | ||||||
| type: ['string', 'boolean'], | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/apiKey/title', | ||||||
| 'Either the key to access the API served at the given url or `true` to use the global Anthropic API key'), | ||||||
| }, | ||||||
| enableStreaming: { | ||||||
| type: 'boolean', | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/enableStreaming/title', | ||||||
| 'Indicates whether the streaming API shall be used. `true` by default.'), | ||||||
| }, | ||||||
| useCaching: { | ||||||
| type: 'boolean', | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/useCaching/title', | ||||||
| 'Indicates whether the model supports prompt caching. `true` by default'), | ||||||
| }, | ||||||
| maxRetries: { | ||||||
| type: 'number', | ||||||
| title: nls.localize('theia/ai/anthropic/customEndpoints/maxRetries/title', | ||||||
| 'Maximum number of retries when a request fails. 3 by default'), | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| // ***************************************************************************** | ||
| // Copyright (C) 2024 EclipseSource GmbH. | ||
| // Copyright (C) 2024, 2025 EclipseSource GmbH. | ||
| // | ||
| // This program and the accompanying materials are made available under the | ||
| // terms of the Eclipse Public License v. 2.0 which is available at | ||
|
|
@@ -57,9 +57,8 @@ export class AnthropicLanguageModelsManagerImpl implements AnthropicLanguageMode | |
| return process.env['https_proxy']; | ||
| }; | ||
|
|
||
| // Determine status based on API key presence | ||
| const effectiveApiKey = apiKeyProvider(); | ||
| const status = this.getStatusForApiKey(effectiveApiKey); | ||
| // Determine status based on API key and custom url presence | ||
| const status = this.calculateStatus(modelDescription, apiKeyProvider()); | ||
|
|
||
| if (model) { | ||
| if (!(model instanceof AnthropicModel)) { | ||
|
|
@@ -69,6 +68,8 @@ export class AnthropicLanguageModelsManagerImpl implements AnthropicLanguageMode | |
| await this.languageModelRegistry.patchLanguageModel<AnthropicModel>(modelDescription.id, { | ||
| model: modelDescription.model, | ||
| enableStreaming: modelDescription.enableStreaming, | ||
| url: modelDescription.url, | ||
| useCaching: modelDescription.useCaching, | ||
| apiKey: apiKeyProvider, | ||
| status, | ||
| maxTokens: modelDescription.maxTokens !== undefined ? modelDescription.maxTokens : DEFAULT_MAX_TOKENS, | ||
|
|
@@ -83,6 +84,7 @@ export class AnthropicLanguageModelsManagerImpl implements AnthropicLanguageMode | |
| modelDescription.enableStreaming, | ||
| modelDescription.useCaching, | ||
| apiKeyProvider, | ||
| modelDescription.url, | ||
| modelDescription.maxTokens, | ||
| modelDescription.maxRetries, | ||
| this.tokenUsageService, | ||
|
|
@@ -114,9 +116,13 @@ export class AnthropicLanguageModelsManagerImpl implements AnthropicLanguageMode | |
| } | ||
|
|
||
| /** | ||
| * Returns the status for a language model based on the presence of an API key. | ||
| * Returns the status for a language model based on the presence of an API key or custom url. | ||
| */ | ||
| protected getStatusForApiKey(effectiveApiKey: string | undefined): LanguageModelStatus { | ||
| protected calculateStatus(modelDescription: AnthropicModelDescription, effectiveApiKey: string | undefined): LanguageModelStatus { | ||
| // Always mark custom models (models with url) as ready for now as we do not know about API Key requirements | ||
| if (modelDescription.url) { | ||
| return { status: 'ready' }; | ||
| } | ||
|
Comment on lines
+122
to
+125
Member
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. This change is not sufficient. Within the AnthropicModel we check for the api key and if it does not exist, the model will immediately throw an error before even trying to use the SDK, see here. Please check what is required for this. In the OpenAI SDK we always need to hand over a key, so for keyless models we hand over a "stub key". I don't know whether this is also required for the Anthropic SDK or whether it actually supports not handing over a key if the endpoint does not need one. |
||
| return effectiveApiKey | ||
| ? { status: 'ready' } | ||
| : { status: 'unavailable', message: 'No API key set' }; | ||
|
|
||
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.
We don't update the year in the Theia project and just leave the header alone once a file is created.