Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Feb 27, 2025
2 parents 594c8ee + 357b4d4 commit d23c2a5
Show file tree
Hide file tree
Showing 12 changed files with 377 additions and 161 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,31 @@

# Changelog

### [Version 1.66.2](https://github.com/lobehub/lobe-chat/compare/v1.66.1...v1.66.2)

<sup>Released on **2025-02-27**</sup>

#### 🐛 Bug Fixes

- **misc**: Update Claude sonnet 3.7 model ID.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

- **misc**: Update Claude sonnet 3.7 model ID, closes [#6567](https://github.com/lobehub/lobe-chat/issues/6567) ([d1039d6](https://github.com/lobehub/lobe-chat/commit/d1039d6))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>

### [Version 1.66.1](https://github.com/lobehub/lobe-chat/compare/v1.66.0...v1.66.1)

<sup>Released on **2025-02-27**</sup>
Expand Down
7 changes: 7 additions & 0 deletions changelog/v1.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
[
{
"children": {
"fixes": ["Update Claude sonnet 3.7 model ID."]
},
"date": "2025-02-27",
"version": "1.66.2"
},
{
"children": {
"improvements": ["Added eu-central-1 region for bedrock."]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lobehub/chat",
"version": "1.66.1",
"version": "1.66.2",
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",
Expand Down
2 changes: 1 addition & 1 deletion src/config/aiModels/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const bedrockChatModels: AIChatModelCard[] = [
'Claude 3.7 sonnet 是 Anthropic 最快的下一代模型。与 Claude 3 Haiku 相比,Claude 3.7 Sonnet 在各项技能上都有所提升,并在许多智力基准测试中超越了上一代最大的模型 Claude 3 Opus。',
displayName: 'Claude 3.7 Sonnet',
enabled: true,
id: 'anthropic.claude-3-7-sonnet-20250219-v1:0',
id: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
maxOutput: 8192,
pricing: {
input: 3,
Expand Down
4 changes: 2 additions & 2 deletions src/config/modelProviders/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Bedrock: ModelProviderCard = {
displayName: 'Claude 3.7 Sonnet',
enabled: true,
functionCall: true,
id: 'anthropic.claude-3-7-sonnet-20250219-v1:0',
id: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
maxOutput: 8192,
pricing: {
cachedInput: 0.1,
Expand All @@ -50,7 +50,7 @@ const Bedrock: ModelProviderCard = {
displayName: 'Claude 3.7 Sonnet Extended thinking',
enabled: true,
functionCall: true,
id: 'anthropic.claude-3-7-sonnet-20250219-v1:0',
id: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
maxOutput: 64_000,
pricing: {
cachedInput: 0.1,
Expand Down
2 changes: 1 addition & 1 deletion src/const/settings/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const DEFAULT_AGENT_CHAT_CONFIG: LobeAgentChatConfig = {
enableAutoCreateTopic: true,
enableCompressHistory: true,
enableHistoryCount: true,
enableReasoning: true,
enableReasoning: false,
historyCount: 8,
reasoningBudgetToken: 1024,
searchMode: 'off',
Expand Down
377 changes: 250 additions & 127 deletions src/libs/agent-runtime/utils/anthropicHelpers.test.ts

Large diffs are not rendered by default.

83 changes: 56 additions & 27 deletions src/libs/agent-runtime/utils/anthropicHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ import { parseDataUri } from './uriParser';

export const buildAnthropicBlock = async (
content: UserMessageContentPart,
): Promise<Anthropic.ContentBlock | Anthropic.ImageBlockParam> => {
): Promise<Anthropic.ContentBlock | Anthropic.ImageBlockParam | undefined> => {
switch (content.type) {
case 'thinking':
case 'text': {
case 'thinking': {
// just pass-through the content
return content as any;
}

case 'text': {
if (!!content.text) return content as any;

return undefined;
}

case 'image_url': {
const { mimeType, base64, type } = parseDataUri(content.image_url.url);

Expand Down Expand Up @@ -46,6 +51,16 @@ export const buildAnthropicBlock = async (
}
};

const buildArrayContent = async (content: UserMessageContentPart[]) => {
let messageContent = (await Promise.all(
(content as UserMessageContentPart[]).map(async (c) => await buildAnthropicBlock(c)),
)) as Anthropic.Messages.ContentBlockParam[];

messageContent = messageContent.filter(Boolean);

return messageContent;
};

export const buildAnthropicMessage = async (
message: OpenAIChatMessage,
): Promise<Anthropic.Messages.MessageParam> => {
Expand All @@ -58,10 +73,7 @@ export const buildAnthropicMessage = async (

case 'user': {
return {
content:
typeof content === 'string'
? content
: await Promise.all(content.map(async (c) => await buildAnthropicBlock(c))),
content: typeof content === 'string' ? content : await buildArrayContent(content),
role: 'user',
};
}
Expand All @@ -83,11 +95,13 @@ export const buildAnthropicMessage = async (
case 'assistant': {
// if there is tool_calls , we need to covert the tool_calls to tool_use content block
// refs: https://docs.anthropic.com/claude/docs/tool-use#tool-use-and-tool-result-content-blocks
if (message.tool_calls) {
const messageContent =
if (message.tool_calls && message.tool_calls.length > 0) {
const rawContent =
typeof content === 'string'
? [{ text: message.content, type: 'text' }]
: await Promise.all(content.map(async (c) => await buildAnthropicBlock(c)));
? ([{ text: message.content, type: 'text' }] as UserMessageContentPart[])
: content;

const messageContent = await buildArrayContent(rawContent);

return {
content: [
Expand Down Expand Up @@ -120,39 +134,54 @@ export const buildAnthropicMessages = async (
const messages: Anthropic.Messages.MessageParam[] = [];
let pendingToolResults: Anthropic.ToolResultBlockParam[] = [];

// 首先收集所有 assistant 消息中的 tool_call_id 以便后续查找
const validToolCallIds = new Set<string>();
for (const message of oaiMessages) {
if (message.role === 'assistant' && message.tool_calls?.length) {
message.tool_calls.forEach((call) => {
if (call.id) {
validToolCallIds.add(call.id);
}
});
}
}

for (const message of oaiMessages) {
const index = oaiMessages.indexOf(message);

// refs: https://docs.anthropic.com/claude/docs/tool-use#tool-use-and-tool-result-content-blocks
if (message.role === 'tool') {
pendingToolResults.push({
content: [{ text: message.content as string, type: 'text' }],
tool_use_id: message.tool_call_id!,
type: 'tool_result',
});
// 检查这个工具消息是否有对应的 assistant 工具调用
if (message.tool_call_id && validToolCallIds.has(message.tool_call_id)) {
pendingToolResults.push({
content: [{ text: message.content as string, type: 'text' }],
tool_use_id: message.tool_call_id,
type: 'tool_result',
});

// If this is the last message or the next message is not a 'tool' message,
// we add the accumulated tool results as a single 'user' message
if (index === oaiMessages.length - 1 || oaiMessages[index + 1].role !== 'tool') {
// 如果这是最后一个消息或者下一个消息不是 'tool',则添加累积的工具结果作为一个 'user' 消息
if (index === oaiMessages.length - 1 || oaiMessages[index + 1].role !== 'tool') {
messages.push({
content: pendingToolResults,
role: 'user',
});
pendingToolResults = [];
}
} else {
// 如果工具消息没有对应的 assistant 工具调用,则作为普通文本处理
messages.push({
content: pendingToolResults,
content: message.content as string,
role: 'user',
});
pendingToolResults = [];
}
} else {
const anthropicMessage = await buildAnthropicMessage(message);

messages.push({
...anthropicMessage,
role: index === 0 && anthropicMessage.role === 'assistant' ? 'user' : anthropicMessage.role,
});
messages.push({ ...anthropicMessage, role: anthropicMessage.role });
}
}

return messages;
};

export const buildAnthropicTools = (tools?: OpenAI.ChatCompletionTool[]) =>
tools?.map(
(tool): Anthropic.Tool => ({
Expand Down
31 changes: 31 additions & 0 deletions src/services/__tests__/chat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,37 @@ describe('ChatService', () => {
});
});

it('should handle empty tool calls messages correctly', () => {
const messages = [
{
content: '## Tools\n\nYou can use these tools',
role: 'system',
},
{
content: '',
role: 'assistant',
tool_calls: [],
},
] as ChatMessage[];

const result = chatService['processMessages']({
messages,
model: 'gpt-4',
provider: 'openai',
});

expect(result).toEqual([
{
content: '## Tools\n\nYou can use these tools',
role: 'system',
},
{
content: '',
role: 'assistant',
},
]);
});

it('should handle assistant messages with reasoning correctly', () => {
const messages = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exports[`agentSelectors > defaultAgentConfig > should merge DEFAULT_AGENT_CONFIG
"enableAutoCreateTopic": true,
"enableCompressHistory": true,
"enableHistoryCount": true,
"enableReasoning": true,
"enableReasoning": false,
"historyCount": 8,
"reasoningBudgetToken": 1024,
"searchMode": "off",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ exports[`settingsSelectors > defaultAgent > should merge DEFAULT_AGENT and s.set
"enableAutoCreateTopic": true,
"enableCompressHistory": true,
"enableHistoryCount": true,
"enableReasoning": true,
"enableReasoning": false,
"historyCount": 8,
"reasoningBudgetToken": 1024,
"searchMode": "off",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const useStyles = createStyles(({ css, token }) => ({
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
color: ${token.colorTextSecondary};
text-overflow: ellipsis;
`,
url: css`
Expand Down

0 comments on commit d23c2a5

Please sign in to comment.