Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/plugins/robot/src/Main.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
v-model:fullscreen="fullscreen"
v-model:show="robotVisible"
v-model:input="inputMessage"
:status="messageState.status"
:status="chatStatus"
:prompt-items="promptItems"
:bubble-renderers="bubbleRenderers"
:allowFiles="isVisualModel && robotSettingState.chatMode === ChatMode.Agent"
Expand Down Expand Up @@ -147,9 +147,9 @@ const showTeleport = ref(false)
const showSetting = ref(false)

const {
chatStatus,
inputMessage,
messages,
messageState,
changeChatMode,
abortRequest,
initChatClient,
Expand Down
3 changes: 1 addition & 2 deletions packages/plugins/robot/src/components/chat/RobotChat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
:placeholder="GeneratingStatus.includes(props.status) ? '正在思考中...' : '请输入您的问题'"
:clearable="true"
:loading="GeneratingStatus.includes(props.status)"
:showWordLimit="true"
:maxLength="4000"
:showWordLimit="false"
@submit="handleSendMessage"
@cancel="handleAbortRequest"
:allowFiles="selectedAttachments.length < 1 && props.allowFiles"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface ConversationAdapterOptions {
statusManager: {
isProcessing: () => boolean
setProcessing: () => void
resetProcessing: () => void
}
}

Expand Down Expand Up @@ -43,7 +44,8 @@ export function useConversationAdapter(options: ConversationAdapterOptions) {
const contextMessages = toRaw(messages.value.slice(0, -1))
await onFinishRequest(finishReason ?? 'unknown', messages.value, contextMessages, messageState)
const lastMessage = messages.value.at(-1)
if (lastMessage) {
if (lastMessage && finishReason === 'stop' && !lastMessage.tool_calls && statusManager.isProcessing()) {
statusManager.resetProcessing()
await onMessageProcessed(finishReason ?? 'unknown', lastMessage.content ?? '', messages.value, {})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const handleDeltaReasoning = (choice: ChatCompletionStreamResponseChoice, lastMe
})
}
lastMessage.renderContent.at(-1)!.content += choice.delta.reasoning_content
lastMessage.reasoning_content = (lastMessage.reasoning_content || '') + choice.delta.reasoning_content
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,19 @@ export interface ToolCallHandlerConfig {
onDone: (finishReason: string, messages: any[], contextMessages: any[], messageState: any) => Promise<void>
}
getMessageState: () => any
statusManager?: {
isProcessing: () => boolean
setProcessing: () => void
resetProcessing: () => void
}
}

/**
* 创建工具调用处理器
* 使用工厂函数模式,将所有依赖通过配置注入
*/
export function createToolCallHandler(config: ToolCallHandlerConfig) {
const { client, getAbortController, formatMessages, hooks, streamHandlers, getMessageState } = config
const { client, getAbortController, formatMessages, hooks, streamHandlers, getMessageState, statusManager } = config

return async (tool_calls: ResponseToolCall[], messages: any[], contextMessages: RobotMessage[]) => {
const hasToolCall = tool_calls?.length > 0
Expand Down Expand Up @@ -118,6 +123,8 @@ export function createToolCallHandler(config: ToolCallHandlerConfig) {

delete currentMessage.tool_calls

statusManager?.setProcessing()

// 使用工具调用结果继续对话
await client.chatStream(
{ messages: toolMessages as any, options: { signal: abortController.signal } },
Expand Down
36 changes: 27 additions & 9 deletions packages/plugins/robot/src/composables/useChat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { nextTick } from 'vue'
import { nextTick, ref } from 'vue'
import { GeneratingStatus, STATUS, type ChatMessage, type MessageState } from '@opentiny/tiny-robot-kit'
import { formatMessages, removeLoading } from '../utils'
import { getClientConfig as getConfig, updateClientConfig as updateConfig, client } from '../services/aiClient'
Expand Down Expand Up @@ -39,7 +39,7 @@ enum CHAT_STATUS {
FINISHED = 'finished' // 本轮对话结束
}

let chatStatus: CHAT_STATUS = CHAT_STATUS.PROCESSING
const chatStatus = ref<CHAT_STATUS>(CHAT_STATUS.FINISHED)

const abortControllerMap: Record<string, AbortController> = {}

Expand All @@ -52,9 +52,9 @@ const handleStreamData = createStreamDataHandler({
onStreamTools
},
statusManager: {
isStreaming: () => chatStatus === CHAT_STATUS.STREAMING,
isStreaming: () => chatStatus.value === CHAT_STATUS.STREAMING,
setStreaming: () => {
chatStatus = CHAT_STATUS.STREAMING
chatStatus.value = CHAT_STATUS.STREAMING
}
}
})
Expand Down Expand Up @@ -110,11 +110,15 @@ const handleFinishRequest = async (

if (finishReason === 'aborted' || messageState?.status === STATUS.ABORTED) {
messageState.status = STATUS.ABORTED
} else if (finishReason === 'stop' && !lastMessage.tool_calls) {
messageState.status = STATUS.FINISHED
chatStatus.value = CHAT_STATUS.FINISHED
await onMessageProcessed(finishReason, lastMessage.content ?? '', messages.value, {})
}
Comment thread
hexqi marked this conversation as resolved.
}

const handleRequestError = async (error: Error, messages: ChatMessage[], messageState: MessageState) => {
chatStatus = CHAT_STATUS.FINISHED
chatStatus.value = CHAT_STATUS.FINISHED
delete abortControllerMap.main
await onRequestEnd('error', messages.at(-1).content, messages, { error }) // 本次请求结束
messageState.status = STATUS.ERROR
Expand All @@ -140,12 +144,15 @@ const {
if (GeneratingStatus.includes(messageManager.messageState.status)) {
messageManager.messageState.status = STATUS.FINISHED
}
chatStatus = CHAT_STATUS.FINISHED
chatStatus.value = CHAT_STATUS.FINISHED
},
statusManager: {
isProcessing: () => chatStatus === CHAT_STATUS.PROCESSING,
isProcessing: () => chatStatus.value === CHAT_STATUS.PROCESSING,
setProcessing: () => {
chatStatus = CHAT_STATUS.PROCESSING
chatStatus.value = CHAT_STATUS.PROCESSING
},
resetProcessing: () => {
chatStatus.value = CHAT_STATUS.FINISHED
}
}
})
Expand All @@ -168,7 +175,16 @@ const handleToolCall = createToolCallHandler({
onError: handleRequestError,
onDone: handleFinishRequest
},
getMessageState: () => messageManager.messageState
getMessageState: () => messageManager.messageState,
statusManager: {
isProcessing: () => chatStatus.value === CHAT_STATUS.PROCESSING,
setProcessing: () => {
chatStatus.value = CHAT_STATUS.PROCESSING
},
resetProcessing: () => {
chatStatus.value = CHAT_STATUS.FINISHED
}
}
})

// 包装 conversation 方法,添加业务特定逻辑
Expand Down Expand Up @@ -235,6 +251,7 @@ const abortRequest = () => {
for (const key of Object.keys(abortControllerMap)) {
delete abortControllerMap[key]
}
chatStatus.value = CHAT_STATUS.FINISHED

onRequestEnd('aborted', messageManager.messages.value.at(-1)?.content as string, messageManager.messages.value)
}
Expand All @@ -254,6 +271,7 @@ const changeChatMode = (chatMode: string) => {

export default function () {
return {
chatStatus,
initChatClient,
updateConfig,
...messageManager,
Expand Down
3 changes: 2 additions & 1 deletion packages/plugins/robot/src/utils/chat.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export const formatMessages = (messages: LLMMessage[]) => {
role: message.role,
content: message.content,
...(message.tool_calls ? { tool_calls: message.tool_calls } : {}),
...(message.tool_call_id ? { tool_call_id: message.tool_call_id } : {})
...(message.tool_call_id ? { tool_call_id: message.tool_call_id } : {}),
...(message.reasoning_content ? { reasoning_content: message.reasoning_content } : {})
}))
}

Expand Down