feat(AnthropicProvider, MessagesService): Add empty message filtering and stream processing improvements

- Introduce filterEmptyMessages function to remove empty messages
- Update AnthropicProvider to use filterEmptyMessages in message preparation
- Refactor stream processing with minor improvements and return statement fixes
- Simplify tool response and message handling logic
This commit is contained in:
kangfenmao 2025-03-11 13:00:04 +08:00
parent e61618f1b4
commit 632b0c17aa
2 changed files with 35 additions and 26 deletions

View File

@ -11,7 +11,11 @@ import { getStoreSetting } from '@renderer/hooks/useSettings'
import i18n from '@renderer/i18n'
import { getAssistantSettings, getDefaultModel, getTopNamingModel } from '@renderer/services/AssistantService'
import { EVENT_NAMES } from '@renderer/services/EventService'
import { filterContextMessages, filterUserRoleStartMessages } from '@renderer/services/MessagesService'
import {
filterContextMessages,
filterEmptyMessages,
filterUserRoleStartMessages
} from '@renderer/services/MessagesService'
import { Assistant, FileTypes, MCPToolResponse, Message, Model, Provider, Suggestion } from '@renderer/types'
import { removeSpecialCharactersForTopicName } from '@renderer/utils'
import { first, flatten, sum, takeRight } from 'lodash'
@ -136,7 +140,10 @@ export default class AnthropicProvider extends BaseProvider {
const { contextCount, maxTokens, streamOutput } = getAssistantSettings(assistant)
const userMessagesParams: MessageParam[] = []
const _messages = filterUserRoleStartMessages(filterContextMessages(takeRight(messages, contextCount + 2)))
const _messages = filterUserRoleStartMessages(
filterContextMessages(filterEmptyMessages(takeRight(messages, contextCount + 2)))
)
onFilterMessages(_messages)
@ -200,8 +207,9 @@ export default class AnthropicProvider extends BaseProvider {
const { abortController, cleanup } = this.createAbortController(lastUserMessage?.id)
const { signal } = abortController
const toolResponses: MCPToolResponse[] = []
const processStream = async (body: MessageCreateParamsNonStreaming) => {
new Promise<void>((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
const toolCalls: ToolUseBlock[] = []
let hasThinkingContent = false
const stream = this.sdk.messages
@ -211,6 +219,7 @@ export default class AnthropicProvider extends BaseProvider {
stream.controller.abort()
return resolve()
}
if (time_first_token_millsec == 0) {
time_first_token_millsec = new Date().getTime() - start_time_millsec
}
@ -224,6 +233,7 @@ export default class AnthropicProvider extends BaseProvider {
: 0
const time_completion_millsec = new Date().getTime() - start_time_millsec
onChunk({
text,
metrics: {
@ -236,11 +246,13 @@ export default class AnthropicProvider extends BaseProvider {
})
.on('thinking', (thinking) => {
hasThinkingContent = true
if (time_first_token_millsec == 0) {
time_first_token_millsec = new Date().getTime() - start_time_millsec
}
const time_completion_millsec = new Date().getTime() - start_time_millsec
onChunk({
reasoning_content: thinking,
text: '',
@ -262,30 +274,10 @@ export default class AnthropicProvider extends BaseProvider {
for (const toolCall of toolCalls) {
const mcpTool = anthropicToolUseToMcpTool(mcpTools, toolCall)
if (mcpTool) {
upsertMCPToolResponse(
toolResponses,
{
tool: mcpTool,
status: 'invoking'
},
onChunk
)
upsertMCPToolResponse(toolResponses, { tool: mcpTool, status: 'invoking' }, onChunk)
const resp = await callMCPTool(mcpTool)
toolCallResults.push({
type: 'tool_result',
tool_use_id: toolCall.id,
content: resp.content
})
upsertMCPToolResponse(
toolResponses,
{
tool: mcpTool,
status: 'done',
response: resp
},
onChunk
)
toolCallResults.push({ type: 'tool_result', tool_use_id: toolCall.id, content: resp.content })
upsertMCPToolResponse(toolResponses, { tool: mcpTool, status: 'done', response: resp }, onChunk)
}
}
@ -294,6 +286,7 @@ export default class AnthropicProvider extends BaseProvider {
role: message.role,
content: message.content
})
userMessages.push({
role: 'user',
content: toolCallResults
@ -301,6 +294,7 @@ export default class AnthropicProvider extends BaseProvider {
const newBody = body
body.messages = userMessages
await processStream(newBody)
}
}
@ -309,6 +303,7 @@ export default class AnthropicProvider extends BaseProvider {
const time_thinking_millsec = time_first_content_millsec
? time_first_content_millsec - start_time_millsec
: 0
onChunk({
text: '',
usage: {
@ -324,6 +319,7 @@ export default class AnthropicProvider extends BaseProvider {
},
mcpToolResponse: toolResponses
})
resolve()
})
.on('error', (error) => reject(error))

View File

@ -39,6 +39,19 @@ export function filterUserRoleStartMessages(messages: Message[]): Message[] {
return messages.slice(firstUserMessageIndex)
}
export function filterEmptyMessages(messages: Message[]): Message[] {
return messages.filter((message) => {
const content = message.content as string | any[]
if (typeof content === 'string') {
return !isEmpty(content.trim())
}
if (Array.isArray(content)) {
return content.some((c) => !isEmpty(c.text.trim()))
}
return true
})
}
export function filterUsefulMessages(messages: Message[]): Message[] {
const _messages = messages
const groupedMessages = getGroupedMessages(messages)