fix: correct thinking time and chat translation keys
The update fixes how total thinking time is calculated during a chat message flow. Previously the elapsed time from the initial completion was incorrectly added to the overall thinking time, leading to inflated metrics. The new logic splits the computation into separate phases (initial completion, tool execution, and follow‑up completions) and accumulates them into `totalThinkingTime`, ensuring accurate measurement. Additionally, translation keys for chat components are now namespaced with `chat:` to avoid collisions and clearly indicate the context in which they are used. The diff also removes a stray comment line and keeps metadata updates consistent across recursive calls.
This commit is contained in:
parent
0c80950226
commit
97c94079a9
@ -10,7 +10,7 @@ import ImageModal from '@/containers/dialogs/ImageModal'
|
|||||||
|
|
||||||
// Define ReActStep type (Reasoning-Action Step)
|
// Define ReActStep type (Reasoning-Action Step)
|
||||||
type ReActStep = {
|
type ReActStep = {
|
||||||
type: 'reasoning' | 'tool_call' | 'tool_output' | 'done' // Changed 'thought' to 'reasoning'
|
type: 'reasoning' | 'tool_call' | 'tool_output' | 'done'
|
||||||
content: string
|
content: string
|
||||||
metadata?: any
|
metadata?: any
|
||||||
time?: number
|
time?: number
|
||||||
@ -114,7 +114,7 @@ const ThinkingBlock = ({
|
|||||||
<div className="mb-4 rounded-lg bg-main-view-fg/4 border border-dashed border-main-view-fg/10 p-2 flex items-center gap-3">
|
<div className="mb-4 rounded-lg bg-main-view-fg/4 border border-dashed border-main-view-fg/10 p-2 flex items-center gap-3">
|
||||||
<Loader className="size-4 animate-spin text-main-view-fg/60" />
|
<Loader className="size-4 animate-spin text-main-view-fg/60" />
|
||||||
<span className="font-medium text-main-view-fg/80">
|
<span className="font-medium text-main-view-fg/80">
|
||||||
{t('thinking')}
|
{t('chat:thinking')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -144,7 +144,7 @@ const ThinkingBlock = ({
|
|||||||
const timeInSeconds = formatDuration(step.time ?? 0)
|
const timeInSeconds = formatDuration(step.time ?? 0)
|
||||||
const timeDisplay =
|
const timeDisplay =
|
||||||
timeInSeconds > 0
|
timeInSeconds > 0
|
||||||
? `(${t('for')} ${timeInSeconds} ${t('seconds')})`
|
? `(${t('chat:for')} ${timeInSeconds} ${t('chat:seconds')})`
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -259,7 +259,7 @@ const ThinkingBlock = ({
|
|||||||
activeStep.type === 'tool_call' ||
|
activeStep.type === 'tool_call' ||
|
||||||
activeStep.type === 'tool_output'
|
activeStep.type === 'tool_output'
|
||||||
) {
|
) {
|
||||||
return `${t('calling_tool')}` // Use a specific translation key for tool
|
return `${t('chat:calling_tool')}` // Use a specific translation key for tool
|
||||||
} else if (activeStep.type === 'reasoning') {
|
} else if (activeStep.type === 'reasoning') {
|
||||||
return `${t('chat:thinking')}` // Use the generic thinking key
|
return `${t('chat:thinking')}` // Use the generic thinking key
|
||||||
}
|
}
|
||||||
|
|||||||
@ -755,7 +755,9 @@ export const useChat = () => {
|
|||||||
throw new Error('No response received from the model')
|
throw new Error('No response received from the model')
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalThinkingTime = Date.now() - startTime // Calculate total elapsed time
|
const completionFinishTime = Date.now()
|
||||||
|
// Calculate the time taken for the initial completion (streaming or non-streaming)
|
||||||
|
const initialCompletionTime = completionFinishTime - startTime
|
||||||
|
|
||||||
const messageMetadata: Record<string, any> = {
|
const messageMetadata: Record<string, any> = {
|
||||||
tokenSpeed: useAppState.getState().tokenSpeed,
|
tokenSpeed: useAppState.getState().tokenSpeed,
|
||||||
@ -764,7 +766,7 @@ export const useChat = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (accumulatedText.includes('<think>') || toolCalls.length > 0) {
|
if (accumulatedText.includes('<think>') || toolCalls.length > 0) {
|
||||||
messageMetadata.totalThinkingTime = totalThinkingTime
|
messageMetadata.totalThinkingTime = initialCompletionTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the message object that will be built upon by postMessageProcessing
|
// This is the message object that will be built upon by postMessageProcessing
|
||||||
|
|||||||
@ -406,7 +406,6 @@ export const extractToolCall = (
|
|||||||
}
|
}
|
||||||
return calls
|
return calls
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to check if a tool call is a browser MCP tool
|
* Helper function to check if a tool call is a browser MCP tool
|
||||||
* @param toolName - The name of the tool
|
* @param toolName - The name of the tool
|
||||||
@ -558,6 +557,10 @@ export const postMessageProcessing = async (
|
|||||||
currentStepCount: number = 0,
|
currentStepCount: number = 0,
|
||||||
isProactiveMode: boolean = false
|
isProactiveMode: boolean = false
|
||||||
): Promise<ThreadMessage> => {
|
): Promise<ThreadMessage> => {
|
||||||
|
// Initialize/get the current total thinking time from metadata
|
||||||
|
// This value is passed from sendMessage (initial completion time) or previous recursive call
|
||||||
|
let currentTotalTime = (message.metadata?.totalThinkingTime as number) ?? 0
|
||||||
|
|
||||||
// Handle completed tool calls
|
// Handle completed tool calls
|
||||||
if (calls.length > 0) {
|
if (calls.length > 0) {
|
||||||
// Check limit BEFORE processing
|
// Check limit BEFORE processing
|
||||||
@ -604,6 +607,7 @@ export const postMessageProcessing = async (
|
|||||||
message.metadata = {
|
message.metadata = {
|
||||||
...(message.metadata ?? {}),
|
...(message.metadata ?? {}),
|
||||||
tool_calls: currentToolCalls,
|
tool_calls: currentToolCalls,
|
||||||
|
totalThinkingTime: currentTotalTime,
|
||||||
}
|
}
|
||||||
if (updateStreamingUI) updateStreamingUI({ ...message }) // Show pending call
|
if (updateStreamingUI) updateStreamingUI({ ...message }) // Show pending call
|
||||||
|
|
||||||
@ -634,6 +638,8 @@ export const postMessageProcessing = async (
|
|||||||
)
|
)
|
||||||
: true)
|
: true)
|
||||||
|
|
||||||
|
const toolExecutionStartTime = Date.now()
|
||||||
|
|
||||||
const { promise, cancel } = isRagTool
|
const { promise, cancel } = isRagTool
|
||||||
? ragFeatureAvailable
|
? ragFeatureAvailable
|
||||||
? {
|
? {
|
||||||
@ -683,6 +689,8 @@ export const postMessageProcessing = async (
|
|||||||
error: 'disallowed',
|
error: 'disallowed',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toolExecutionTime = Date.now() - toolExecutionStartTime
|
||||||
|
|
||||||
if (typeof result === 'string') {
|
if (typeof result === 'string') {
|
||||||
result = {
|
result = {
|
||||||
content: [{ type: 'text', text: result }],
|
content: [{ type: 'text', text: result }],
|
||||||
@ -690,9 +698,15 @@ export const postMessageProcessing = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentTotalTime += toolExecutionTime
|
||||||
|
|
||||||
// Update the entry in the metadata array
|
// Update the entry in the metadata array
|
||||||
toolCallEntry.response = result
|
toolCallEntry.response = result
|
||||||
toolCallEntry.state = 'ready'
|
toolCallEntry.state = 'ready'
|
||||||
|
message.metadata = {
|
||||||
|
...(message.metadata ?? {}),
|
||||||
|
totalThinkingTime: currentTotalTime,
|
||||||
|
}
|
||||||
if (updateStreamingUI) updateStreamingUI({ ...message }) // Show result
|
if (updateStreamingUI) updateStreamingUI({ ...message }) // Show result
|
||||||
|
|
||||||
const streamEvents = (message.metadata?.streamEvents || []) as any[]
|
const streamEvents = (message.metadata?.streamEvents || []) as any[]
|
||||||
@ -738,6 +752,8 @@ export const postMessageProcessing = async (
|
|||||||
try {
|
try {
|
||||||
const messagesWithToolResults = builder.getMessages()
|
const messagesWithToolResults = builder.getMessages()
|
||||||
|
|
||||||
|
const followUpStartTime = Date.now()
|
||||||
|
|
||||||
const followUpCompletion = await sendCompletion(
|
const followUpCompletion = await sendCompletion(
|
||||||
thread,
|
thread,
|
||||||
provider,
|
provider,
|
||||||
@ -748,6 +764,8 @@ export const postMessageProcessing = async (
|
|||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let streamFinishTime = Date.now()
|
||||||
|
|
||||||
if (followUpCompletion) {
|
if (followUpCompletion) {
|
||||||
let followUpText = ''
|
let followUpText = ''
|
||||||
const newToolCalls: ChatCompletionMessageToolCall[] = []
|
const newToolCalls: ChatCompletionMessageToolCall[] = []
|
||||||
@ -766,6 +784,7 @@ export const postMessageProcessing = async (
|
|||||||
}
|
}
|
||||||
if (textContent?.text) textContent.text.value += followUpText
|
if (textContent?.text) textContent.text.value += followUpText
|
||||||
if (updateStreamingUI) updateStreamingUI({ ...message })
|
if (updateStreamingUI) updateStreamingUI({ ...message })
|
||||||
|
streamFinishTime = Date.now()
|
||||||
} else {
|
} else {
|
||||||
// Handle streaming response
|
// Handle streaming response
|
||||||
const reasoningProcessor = new ReasoningProcessor()
|
const reasoningProcessor = new ReasoningProcessor()
|
||||||
@ -777,7 +796,6 @@ export const postMessageProcessing = async (
|
|||||||
const deltaContent = chunk.choices[0]?.delta?.content || ''
|
const deltaContent = chunk.choices[0]?.delta?.content || ''
|
||||||
|
|
||||||
if (textContent?.text) {
|
if (textContent?.text) {
|
||||||
// if (deltaReasoning) textContent.text.value += deltaReasoning
|
|
||||||
if (deltaContent) {
|
if (deltaContent) {
|
||||||
textContent.text.value += deltaContent
|
textContent.text.value += deltaContent
|
||||||
followUpText += deltaContent
|
followUpText += deltaContent
|
||||||
@ -810,6 +828,8 @@ export const postMessageProcessing = async (
|
|||||||
message.metadata = {
|
message.metadata = {
|
||||||
...(message.metadata ?? {}),
|
...(message.metadata ?? {}),
|
||||||
streamEvents: streamEvents,
|
streamEvents: streamEvents,
|
||||||
|
totalThinkingTime:
|
||||||
|
currentTotalTime + (Date.now() - followUpStartTime), // Optimistic update
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateStreamingUI) {
|
if (updateStreamingUI) {
|
||||||
@ -822,7 +842,7 @@ export const postMessageProcessing = async (
|
|||||||
updateStreamingUI(uiMessage)
|
updateStreamingUI(uiMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
streamFinishTime = Date.now()
|
||||||
if (textContent?.text && updateStreamingUI) {
|
if (textContent?.text && updateStreamingUI) {
|
||||||
// Final UI update after streaming completes
|
// Final UI update after streaming completes
|
||||||
const uiMessage: ThreadMessage = {
|
const uiMessage: ThreadMessage = {
|
||||||
@ -833,9 +853,17 @@ export const postMessageProcessing = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const followUpTotalTime = streamFinishTime - followUpStartTime
|
||||||
|
currentTotalTime += followUpTotalTime //
|
||||||
|
message.metadata = {
|
||||||
|
...(message.metadata ?? {}),
|
||||||
|
totalThinkingTime: currentTotalTime,
|
||||||
|
}
|
||||||
|
|
||||||
// Recursively process new tool calls if any
|
// Recursively process new tool calls if any
|
||||||
if (newToolCalls.length > 0) {
|
if (newToolCalls.length > 0) {
|
||||||
builder.addAssistantMessage(followUpText, undefined, newToolCalls)
|
builder.addAssistantMessage(followUpText, undefined, newToolCalls)
|
||||||
|
// Recursive call continues accumulation on the same message object
|
||||||
await postMessageProcessing(
|
await postMessageProcessing(
|
||||||
newToolCalls,
|
newToolCalls,
|
||||||
builder,
|
builder,
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"tool_called": "Called tools",
|
"tool_called": "Called tools",
|
||||||
"calling_tool": "Calling a tool",
|
"calling_tool": "Calling a tool",
|
||||||
"thinking": "Thinking",
|
"thinking": "Thinking",
|
||||||
|
"thought": "Thought",
|
||||||
"for": "for",
|
"for": "for",
|
||||||
"seconds": "seconds"
|
"seconds": "seconds"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user