-
-
Notifications
You must be signed in to change notification settings - Fork 7.8k
/
index.ts
104 lines (87 loc) 路 3.33 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// sort-imports-ignore
import '@anthropic-ai/sdk/shims/web';
import Anthropic from '@anthropic-ai/sdk';
import { AnthropicStream, StreamingTextResponse } from 'ai';
import { ClientOptions } from 'openai';
import { LobeRuntimeAI } from '../BaseAI';
import { AgentRuntimeErrorType } from '../error';
import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types';
import { AgentRuntimeError } from '../utils/createError';
import { debugStream } from '../utils/debugStream';
import { desensitizeUrl } from '../utils/desensitizeUrl';
import { buildAnthropicMessages } from '../utils/anthropicHelpers';
const DEFAULT_BASE_URL = 'https://api.anthropic.com';
export class LobeAnthropicAI implements LobeRuntimeAI {
private client: Anthropic;
baseURL: string;
constructor({ apiKey, baseURL = DEFAULT_BASE_URL }: ClientOptions) {
if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidAnthropicAPIKey);
this.client = new Anthropic({ apiKey, baseURL });
this.baseURL = this.client.baseURL;
}
async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
try {
const anthropicPayload = this.buildAnthropicPayload(payload);
const response = await this.client.messages.create(
{ ...anthropicPayload, stream: true },
{ signal: options?.signal },
);
const [prod, debug] = response.tee();
if (process.env.DEBUG_ANTHROPIC_CHAT_COMPLETION === '1') {
debugStream(debug.toReadableStream()).catch(console.error);
}
return new StreamingTextResponse(AnthropicStream(prod, options?.callback), {
headers: options?.headers,
});
} catch (error) {
let desensitizedEndpoint = this.baseURL;
if (this.baseURL !== DEFAULT_BASE_URL) {
desensitizedEndpoint = desensitizeUrl(this.baseURL);
}
if ('status' in (error as any)) {
switch ((error as Response).status) {
case 401: {
throw AgentRuntimeError.chat({
endpoint: desensitizedEndpoint,
error: error as any,
errorType: AgentRuntimeErrorType.InvalidAnthropicAPIKey,
provider: ModelProvider.Anthropic,
});
}
case 403: {
throw AgentRuntimeError.chat({
endpoint: desensitizedEndpoint,
error: error as any,
errorType: AgentRuntimeErrorType.LocationNotSupportError,
provider: ModelProvider.Anthropic,
});
}
default: {
break;
}
}
}
throw AgentRuntimeError.chat({
endpoint: desensitizedEndpoint,
error: error as any,
errorType: AgentRuntimeErrorType.AnthropicBizError,
provider: ModelProvider.Anthropic,
});
}
}
private buildAnthropicPayload(payload: ChatStreamPayload) {
const { messages, model, max_tokens, temperature, top_p } = payload;
const system_message = messages.find((m) => m.role === 'system');
const user_messages = messages.filter((m) => m.role !== 'system');
return {
max_tokens: max_tokens || 4096,
messages: buildAnthropicMessages(user_messages),
model: model,
stream: true,
system: system_message?.content as string,
temperature: temperature,
top_p: top_p,
};
}
}
export default LobeAnthropicAI;