diff --git a/packages/aiCore/src/core/providers/types.ts b/packages/aiCore/src/core/providers/types.ts index 4f8eafb51e..9a37007fe5 100644 --- a/packages/aiCore/src/core/providers/types.ts +++ b/packages/aiCore/src/core/providers/types.ts @@ -65,7 +65,7 @@ export class ProviderError extends Error { } // 动态ProviderId类型 - 支持运行时扩展 -export type ProviderId = keyof ExtensibleProviderSettingsMap | string +export type ProviderId = keyof ExtensibleProviderSettingsMap & string // Provider类型注册工具 export interface ProviderTypeRegistrar { diff --git a/src/renderer/src/hooks/useMessageOperations.ts b/src/renderer/src/hooks/useMessageOperations.ts index e1b7ea30ff..b1836f3fa7 100644 --- a/src/renderer/src/hooks/useMessageOperations.ts +++ b/src/renderer/src/hooks/useMessageOperations.ts @@ -1,7 +1,7 @@ import { loggerService } from '@logger' import { createSelector } from '@reduxjs/toolkit' import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService' -import { appendTrace, pauseTrace, restartTrace } from '@renderer/services/SpanManagerService' +import { appendMessageTrace, pauseTrace, restartTrace } from '@renderer/services/SpanManagerService' import { estimateUserPromptUsage } from '@renderer/services/TokenService' import store, { type RootState, useAppDispatch, useAppSelector } from '@renderer/store' import { updateOneBlock } from '@renderer/store/messageBlock' @@ -178,7 +178,7 @@ export function useMessageOperations(topic: Topic) { */ const appendAssistantResponse = useCallback( async (existingAssistantMessage: Message, newModel: Model, assistant: Assistant) => { - await appendTrace(existingAssistantMessage, newModel) + await appendMessageTrace(existingAssistantMessage, newModel) if (existingAssistantMessage.role !== 'assistant') { logger.error('appendAssistantResponse should only be called for an existing assistant message.') return diff --git a/src/renderer/src/services/ApiService.ts b/src/renderer/src/services/ApiService.ts index 8449b41db9..8475b59b87 100644 --- a/src/renderer/src/services/ApiService.ts +++ b/src/renderer/src/services/ApiService.ts @@ -89,8 +89,6 @@ export async function fetchChatCompletion({ } onChunkReceived: (chunk: Chunk) => void topicId?: string // 添加 topicId 参数 - // TODO - // onChunkStatus: (status: 'searching' | 'processing' | 'success' | 'error') => void }) { logger.info('fetchChatCompletion called with detailed context', { messageCount: messages?.length || 0, @@ -287,7 +285,6 @@ export async function fetchMessagesSummary({ messages, assistant }: { messages: // 总结上下文总是取最后5条消息 const contextMessages = takeRight(messages, 5) - const provider = getProviderByModel(model) if (!hasApiKey(provider)) { @@ -296,7 +293,7 @@ export async function fetchMessagesSummary({ messages, assistant }: { messages: const AI = new AiProviderNew(model) - const topicId = messages?.find((message) => message.topicId)?.topicId || undefined + const topicId = messages?.find((message) => message.topicId)?.topicId || '' // LLM对多条消息的总结有问题,用单条结构化的消息表示会话内容会更好 const structredMessages = contextMessages.map((message) => { @@ -355,6 +352,15 @@ export async function fetchMessagesSummary({ messages, assistant }: { messages: mcpTools: [] } try { + // 从 messages 中找到有 traceId 的助手消息,用于绑定现有 trace + const messageWithTrace = messages.find((m) => m.role === 'assistant' && m.traceId) + + if (messageWithTrace && messageWithTrace.traceId) { + // 导入并调用 appendTrace 来绑定现有 trace,传入summary使用的模型名 + const { appendTrace } = await import('@renderer/services/SpanManagerService') + await appendTrace({ topicId, traceId: messageWithTrace.traceId, model }) + } + const { getText } = await AI.completionsForTrace(model.id, llmMessages, { ...middlewareConfig, assistant: summaryAssistant, diff --git a/src/renderer/src/services/SpanManagerService.ts b/src/renderer/src/services/SpanManagerService.ts index 21aee1fc8d..bfb59cb25d 100644 --- a/src/renderer/src/services/SpanManagerService.ts +++ b/src/renderer/src/services/SpanManagerService.ts @@ -97,7 +97,7 @@ class SpanManagerService { window.api.trace.openWindow(message.topicId, message.traceId, false, modelName) } - async appendTrace(message: Message, model: Model) { + async appendMessageTrace(message: Message, model: Model) { if (!getEnableDeveloperMode()) { return } @@ -113,6 +113,29 @@ class SpanManagerService { window.api.trace.openWindow(message.topicId, message.traceId, false, model.name) } + async appendTrace({ topicId, traceId, model }: { topicId: string; traceId: string; model: Model }) { + if (!getEnableDeveloperMode()) { + return + } + if (!traceId) { + return + } + + await window.api.trace.cleanHistory(topicId, traceId, model.name) + + // const input = await this._getContentFromMessage(message) + await window.api.trace.bindTopic(topicId, traceId) + + // 不使用 _addModelRootSpan,直接创建简单的 span 来避免额外的模型层级 + const entity = this.getModelSpanEntity(topicId, model.name) + const span = webTracer.startSpan('') + span['_spanContext'].traceId = traceId + entity.addSpan(span, true) + this._updateContext(span, topicId, traceId) + + window.api.trace.openWindow(topicId, traceId, false, model.name) + } + private async _getContentFromMessage(message: Message, content?: string): Promise { let _content = content if (!_content) { @@ -349,6 +372,7 @@ export const currentSpan = spanManagerService.getCurrentSpan.bind(spanManagerSer export const addTokenUsage = spanManagerService.addTokenUsage.bind(spanManagerService) export const pauseTrace = spanManagerService.finishModelTrace.bind(spanManagerService) export const appendTrace = spanManagerService.appendTrace.bind(spanManagerService) +export const appendMessageTrace = spanManagerService.appendMessageTrace.bind(spanManagerService) export const restartTrace = spanManagerService.restartTrace.bind(spanManagerService) EventEmitter.on(EVENT_NAMES.SEND_MESSAGE, ({ topicId, traceId }) => { diff --git a/src/renderer/src/trace/dataHandler/CommonResultHandler.ts b/src/renderer/src/trace/dataHandler/CommonResultHandler.ts index 4c5ea553c5..c66528abb0 100644 --- a/src/renderer/src/trace/dataHandler/CommonResultHandler.ts +++ b/src/renderer/src/trace/dataHandler/CommonResultHandler.ts @@ -1,6 +1,6 @@ import { TokenUsage } from '@mcp-trace/trace-core' import { Span } from '@opentelemetry/api' -import { CompletionsResult } from '@renderer/aiCore/middleware/schemas' +import { CompletionsResult } from '@renderer/aiCore/legacy/middleware/schemas' import { endSpan } from '@renderer/services/SpanManagerService' export class CompletionsResultHandler {