Skip to content

Commit 0b1a0e0

Browse files
Merge branch 'master' of github.com:Mintplex-Labs/anything-llm
2 parents b4afb99 + 66b4bf2 commit 0b1a0e0

File tree

9 files changed

+166
-106
lines changed

9 files changed

+166
-106
lines changed

.github/workflows/dev-build.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ concurrency:
66

77
on:
88
push:
9-
branches: ['sharp-pdf-image-converter'] # put your current branch to create a build. Core team only.
9+
branches: ['chore/anthropic-model-endpoint'] # put your current branch to create a build. Core team only.
1010
paths-ignore:
1111
- '**.md'
1212
- 'cloud-deployments/*'
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1+
import { useState, useEffect } from "react";
2+
import System from "@/models/system";
3+
14
export default function AnthropicAiOptions({ settings }) {
5+
const [inputValue, setInputValue] = useState(settings?.AnthropicApiKey);
6+
const [anthropicApiKey, setAnthropicApiKey] = useState(
7+
settings?.AnthropicApiKey
8+
);
9+
210
return (
311
<div className="w-full flex flex-col">
412
<div className="w-full flex items-center gap-[36px] mt-1.5">
@@ -15,45 +23,117 @@ export default function AnthropicAiOptions({ settings }) {
1523
required={true}
1624
autoComplete="off"
1725
spellCheck={false}
26+
onChange={(e) => setInputValue(e.target.value)}
27+
onBlur={() => setAnthropicApiKey(inputValue)}
1828
/>
1929
</div>
2030

2131
{!settings?.credentialsOnly && (
22-
<div className="flex flex-col w-60">
23-
<label className="text-white text-sm font-semibold block mb-3">
24-
Chat Model Selection
25-
</label>
26-
<select
27-
name="AnthropicModelPref"
28-
defaultValue={settings?.AnthropicModelPref || "claude-2"}
29-
required={true}
30-
className="border-none bg-theme-settings-input-bg border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
31-
>
32-
{[
33-
"claude-instant-1.2",
34-
"claude-2.0",
35-
"claude-2.1",
36-
"claude-3-haiku-20240307",
37-
"claude-3-sonnet-20240229",
38-
"claude-3-opus-latest",
39-
"claude-3-5-haiku-latest",
40-
"claude-3-5-haiku-20241022",
41-
"claude-3-5-sonnet-latest",
42-
"claude-3-5-sonnet-20241022",
43-
"claude-3-5-sonnet-20240620",
44-
"claude-3-7-sonnet-20250219",
45-
"claude-3-7-sonnet-latest",
46-
].map((model) => {
47-
return (
48-
<option key={model} value={model}>
49-
{model}
50-
</option>
51-
);
52-
})}
53-
</select>
54-
</div>
32+
<AnthropicModelSelection
33+
apiKey={anthropicApiKey}
34+
settings={settings}
35+
/>
5536
)}
5637
</div>
5738
</div>
5839
);
5940
}
41+
42+
const DEFAULT_MODELS = [
43+
{
44+
id: "claude-3-7-sonnet-20250219",
45+
name: "Claude 3.7 Sonnet",
46+
},
47+
{
48+
id: "claude-3-5-sonnet-20241022",
49+
name: "Claude 3.5 Sonnet (New)",
50+
},
51+
{
52+
id: "claude-3-5-haiku-20241022",
53+
name: "Claude 3.5 Haiku",
54+
},
55+
{
56+
id: "claude-3-5-sonnet-20240620",
57+
name: "Claude 3.5 Sonnet (Old)",
58+
},
59+
{
60+
id: "claude-3-haiku-20240307",
61+
name: "Claude 3 Haiku",
62+
},
63+
{
64+
id: "claude-3-opus-20240229",
65+
name: "Claude 3 Opus",
66+
},
67+
{
68+
id: "claude-3-sonnet-20240229",
69+
name: "Claude 3 Sonnet",
70+
},
71+
{
72+
id: "claude-2.1",
73+
name: "Claude 2.1",
74+
},
75+
{
76+
id: "claude-2.0",
77+
name: "Claude 2.0",
78+
},
79+
];
80+
81+
function AnthropicModelSelection({ apiKey, settings }) {
82+
const [models, setModels] = useState(DEFAULT_MODELS);
83+
const [loading, setLoading] = useState(true);
84+
85+
useEffect(() => {
86+
async function findCustomModels() {
87+
setLoading(true);
88+
const { models } = await System.customModels(
89+
"anthropic",
90+
typeof apiKey === "boolean" ? null : apiKey
91+
);
92+
if (models.length > 0) setModels(models);
93+
setLoading(false);
94+
}
95+
findCustomModels();
96+
}, [apiKey]);
97+
98+
if (loading) {
99+
return (
100+
<div className="flex flex-col w-60">
101+
<label className="text-white text-sm font-semibold block mb-3">
102+
Chat Model Selection
103+
</label>
104+
<select
105+
name="AnthropicModelPref"
106+
disabled={true}
107+
className="border-none bg-theme-settings-input-bg border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
108+
>
109+
<option disabled={true} selected={true}>
110+
-- loading available models --
111+
</option>
112+
</select>
113+
</div>
114+
);
115+
}
116+
117+
return (
118+
<div className="flex flex-col w-60">
119+
<label className="text-white text-sm font-semibold block mb-3">
120+
Chat Model Selection
121+
</label>
122+
<select
123+
name="AnthropicModelPref"
124+
required={true}
125+
className="border-none bg-theme-settings-input-bg border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
126+
>
127+
{models.map((model) => (
128+
<option
129+
key={model.id}
130+
value={model.id}
131+
selected={settings?.AnthropicModelPref === model.id}
132+
>
133+
{model.name}
134+
</option>
135+
))}
136+
</select>
137+
</div>
138+
);
139+
}

frontend/src/hooks/useGetProvidersModels.js

+1-15
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,7 @@ const PROVIDER_DEFAULT_MODELS = {
2525
"learnlm-1.5-pro-experimental",
2626
"gemini-2.0-flash-exp",
2727
],
28-
anthropic: [
29-
"claude-instant-1.2",
30-
"claude-2.0",
31-
"claude-2.1",
32-
"claude-3-haiku-20240307",
33-
"claude-3-sonnet-20240229",
34-
"claude-3-opus-latest",
35-
"claude-3-5-haiku-latest",
36-
"claude-3-5-haiku-20241022",
37-
"claude-3-5-sonnet-latest",
38-
"claude-3-5-sonnet-20241022",
39-
"claude-3-5-sonnet-20240620",
40-
"claude-3-7-sonnet-20250219",
41-
"claude-3-7-sonnet-latest",
42-
],
28+
anthropic: [],
4329
azure: [],
4430
lmstudio: [],
4531
localai: [],

frontend/src/pages/WorkspaceSettings/ChatSettings/WorkspaceLLMSelection/ChatModelSelection/index.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export default function ChatModelSelection({
7373
</optgroup>
7474
)}
7575
{Array.isArray(customModels) && customModels.length > 0 && (
76-
<optgroup label="Custom models">
76+
<optgroup label="Discovered models">
7777
{customModels.map((model) => {
7878
return (
7979
<option

server/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"seed": "node prisma/seed.js"
2020
},
2121
"dependencies": {
22-
"@anthropic-ai/sdk": "^0.32.1",
22+
"@anthropic-ai/sdk": "^0.39.0",
2323
"@azure/openai": "1.0.0-beta.10",
2424
"@datastax/astra-db-ts": "^0.1.3",
2525
"@google/generative-ai": "^0.7.1",
@@ -98,4 +98,4 @@
9898
"prettier": "^3.0.3",
9999
"cross-env": "^7.0.3"
100100
}
101-
}
101+
}

server/utils/AiProviders/anthropic/index.js

+10-28
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ class AnthropicLLM {
2222
});
2323
this.anthropic = anthropic;
2424
this.model =
25-
modelPreference || process.env.ANTHROPIC_MODEL_PREF || "claude-2.0";
25+
modelPreference ||
26+
process.env.ANTHROPIC_MODEL_PREF ||
27+
"claude-3-5-sonnet-20241022";
2628
this.limits = {
2729
history: this.promptWindowLimit() * 0.15,
2830
system: this.promptWindowLimit() * 0.15,
@@ -31,6 +33,11 @@ class AnthropicLLM {
3133

3234
this.embedder = embedder ?? new NativeEmbedder();
3335
this.defaultTemp = 0.7;
36+
this.log(`Initialized with ${this.model}`);
37+
}
38+
39+
log(text, ...args) {
40+
console.log(`\x1b[36m[${this.constructor.name}]\x1b[0m ${text}`, ...args);
3441
}
3542

3643
streamingEnabled() {
@@ -45,23 +52,8 @@ class AnthropicLLM {
4552
return MODEL_MAP.anthropic[this.model] ?? 100_000;
4653
}
4754

48-
isValidChatCompletionModel(modelName = "") {
49-
const validModels = [
50-
"claude-instant-1.2",
51-
"claude-2.0",
52-
"claude-2.1",
53-
"claude-3-haiku-20240307",
54-
"claude-3-sonnet-20240229",
55-
"claude-3-opus-latest",
56-
"claude-3-5-haiku-latest",
57-
"claude-3-5-haiku-20241022",
58-
"claude-3-5-sonnet-latest",
59-
"claude-3-5-sonnet-20241022",
60-
"claude-3-5-sonnet-20240620",
61-
"claude-3-7-sonnet-20250219",
62-
"claude-3-7-sonnet-latest",
63-
];
64-
return validModels.includes(modelName);
55+
isValidChatCompletionModel(_modelName = "") {
56+
return true;
6557
}
6658

6759
/**
@@ -111,11 +103,6 @@ class AnthropicLLM {
111103
}
112104

113105
async getChatCompletion(messages = null, { temperature = 0.7 }) {
114-
if (!this.isValidChatCompletionModel(this.model))
115-
throw new Error(
116-
`Anthropic chat: ${this.model} is not valid for chat completion!`
117-
);
118-
119106
try {
120107
const result = await LLMPerformanceMonitor.measureAsyncFunction(
121108
this.anthropic.messages.create({
@@ -146,11 +133,6 @@ class AnthropicLLM {
146133
}
147134

148135
async streamGetChatCompletion(messages = null, { temperature = 0.7 }) {
149-
if (!this.isValidChatCompletionModel(this.model))
150-
throw new Error(
151-
`Anthropic chat: ${this.model} is not valid for chat completion!`
152-
);
153-
154136
const measuredStreamRequest = await LLMPerformanceMonitor.measureStream(
155137
this.anthropic.messages.stream({
156138
model: this.model,

server/utils/helpers/customModels.js

+33
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const { GeminiLLM } = require("../AiProviders/gemini");
1212

1313
const SUPPORT_CUSTOM_MODELS = [
1414
"openai",
15+
"anthropic",
1516
"localai",
1617
"ollama",
1718
"togetherai",
@@ -40,6 +41,8 @@ async function getCustomModels(provider = "", apiKey = null, basePath = null) {
4041
switch (provider) {
4142
case "openai":
4243
return await openAiModels(apiKey);
44+
case "anthropic":
45+
return await anthropicModels(apiKey);
4346
case "localai":
4447
return await localAIModels(basePath, apiKey);
4548
case "ollama":
@@ -185,6 +188,36 @@ async function openAiModels(apiKey = null) {
185188
return { models: [...gpts, ...customModels], error: null };
186189
}
187190

191+
async function anthropicModels(_apiKey = null) {
192+
const apiKey =
193+
_apiKey === true
194+
? process.env.ANTHROPIC_API_KEY
195+
: _apiKey || process.env.ANTHROPIC_API_KEY || null;
196+
const AnthropicAI = require("@anthropic-ai/sdk");
197+
const anthropic = new AnthropicAI({ apiKey });
198+
const models = await anthropic.models
199+
.list()
200+
.then((results) => results.data)
201+
.then((models) => {
202+
return models
203+
.filter((model) => model.type === "model")
204+
.map((model) => {
205+
return {
206+
id: model.id,
207+
name: model.display_name,
208+
};
209+
});
210+
})
211+
.catch((e) => {
212+
console.error(`Anthropic:listModels`, e.message);
213+
return [];
214+
});
215+
216+
// Api Key was successful so lets save it for future uses
217+
if (models.length > 0 && !!apiKey) process.env.ANTHROPIC_API_KEY = apiKey;
218+
return { models, error: null };
219+
}
220+
188221
async function localAIModels(basePath = null, apiKey = null) {
189222
const { OpenAI: OpenAIApi } = require("openai");
190223
const openai = new OpenAIApi({

server/utils/helpers/updateENV.js

+1-22
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const KEY_MAPPING = {
5252
},
5353
AnthropicModelPref: {
5454
envKey: "ANTHROPIC_MODEL_PREF",
55-
checks: [isNotEmpty, validAnthropicModel],
55+
checks: [isNotEmpty],
5656
},
5757

5858
GeminiLLMApiKey: {
@@ -755,27 +755,6 @@ function validGeminiSafetySetting(input = "") {
755755
: `Invalid Safety setting. Must be one of ${validModes.join(", ")}.`;
756756
}
757757

758-
function validAnthropicModel(input = "") {
759-
const validModels = [
760-
"claude-instant-1.2",
761-
"claude-2.0",
762-
"claude-2.1",
763-
"claude-3-haiku-20240307",
764-
"claude-3-sonnet-20240229",
765-
"claude-3-opus-latest",
766-
"claude-3-5-haiku-latest",
767-
"claude-3-5-haiku-20241022",
768-
"claude-3-5-sonnet-latest",
769-
"claude-3-5-sonnet-20241022",
770-
"claude-3-5-sonnet-20240620",
771-
"claude-3-7-sonnet-20250219",
772-
"claude-3-7-sonnet-latest",
773-
];
774-
return validModels.includes(input)
775-
? null
776-
: `Invalid Model type. Must be one of ${validModels.join(", ")}.`;
777-
}
778-
779758
function supportedEmbeddingModel(input = "") {
780759
const supported = [
781760
"openai",

server/yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
node-fetch "^2.6.7"
2525
web-streams-polyfill "^3.2.1"
2626

27-
"@anthropic-ai/sdk@^0.32.1":
28-
version "0.32.1"
29-
resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.32.1.tgz#d22c8ebae2adccc59d78fb416e89de337ff09014"
30-
integrity sha512-U9JwTrDvdQ9iWuABVsMLj8nJVwAyQz6QXvgLsVhryhCEPkLsbcP/MXxm+jYcAwLoV8ESbaTTjnD4kuAFa+Hyjg==
27+
"@anthropic-ai/sdk@^0.39.0":
28+
version "0.39.0"
29+
resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.39.0.tgz#624d5b33413a9cc322febb64e9d48bdcf5a98cdc"
30+
integrity sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==
3131
dependencies:
3232
"@types/node" "^18.11.18"
3333
"@types/node-fetch" "^2.6.4"

0 commit comments

Comments
 (0)