-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[Chat] Fix tool call positioning in conversation timeline #11115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| fix: | ||
| - [Chat] Fix tool call positioning in conversation timeline ([#11115](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/11115)) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -210,6 +210,17 @@ export class ChatEventHandler { | |
|
|
||
| /** | ||
| * Handle start of a tool call | ||
| * | ||
| * This method determines the correct position in the timeline to place tool calls: | ||
| * 1. If parentMessageId is provided, attach to that specific message | ||
| * 2. Otherwise, use a selection strategy to determine placement: | ||
| * - If the last assistant text message appears after the last user message, | ||
| * attach the tool call to that assistant message | ||
| * - If not (e.g., user sent a new message after assistant's response), | ||
| * create a new fake assistant message to hold the tool calls | ||
| * | ||
| * This ensures tool calls are always associated with the correct assistant response | ||
| * in the conversation timeline, maintaining proper message ordering. | ||
| */ | ||
| private handleToolCallStart(event: ToolCallStartEvent): void { | ||
| const { toolCallId, toolCallName, parentMessageId } = event; | ||
|
|
@@ -235,12 +246,46 @@ export class ChatEventHandler { | |
| // Add to pending map for args accumulation | ||
| this.pendingToolCalls.set(toolCallId, toolCall); | ||
|
|
||
| // Use the last TEXT_MESSAGE_START message ID for association | ||
| const targetMessageId = parentMessageId || this.lastTextMessageStartId; | ||
| // Strategy 1: Use explicitly provided parent message ID | ||
| // This is the most reliable approach when the backend provides it | ||
| if (parentMessageId) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Under what situation the parentMessageId will not available?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This Previously, the implementation would fall back to the latest chat agent message when |
||
| this.addToolCallToMessage(parentMessageId, toolCall); | ||
| return; | ||
| } | ||
|
|
||
| // Strategy 2: Determine placement based on message timeline positions | ||
| // Check if the last assistant message is still the most recent response | ||
| const timelineMessages = this.getTimeline(); | ||
| if (this.lastTextMessageStartId) { | ||
| const lastAssistantTextMessageIndex = timelineMessages.findLastIndex( | ||
| (message) => message.id === this.lastTextMessageStartId | ||
| ); | ||
| const lastUserMessageIndex = timelineMessages.findLastIndex( | ||
| (message) => message.role === 'user' | ||
| ); | ||
|
|
||
| if (targetMessageId) { | ||
| this.addToolCallToMessage(targetMessageId, toolCall); | ||
| // If the last assistant message appears after the last user message, | ||
| // it means this tool call belongs to the current conversation turn | ||
| if (lastAssistantTextMessageIndex > lastUserMessageIndex) { | ||
| this.addToolCallToMessage(this.lastTextMessageStartId, toolCall); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| // Strategy 3: Create a new assistant message placeholder | ||
| // This handles the case where the LLM responds with tool calls but without any text message. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this an abnormal case because LLM didn't follow our prompt?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This depends on the chat agent implementation. From my perspective, if the user asks the chat agent to do something straightforward, having no text message before the tool calling section makes sense to me. |
||
| // Since there's no TEXT_MESSAGE_START event, we need to create a fake assistant message | ||
| // to hold the tool calls so they appear in the correct position in the timeline. | ||
| const fakeAssistantMessageId = `fake-assistant-message-` + new Date().getTime(); | ||
| this.onTimelineUpdate((prev) => { | ||
| const newMessage: AssistantMessage = { | ||
| id: fakeAssistantMessageId, | ||
| role: 'assistant', | ||
| toolCalls: [toolCall], | ||
| }; | ||
| return [...prev, newMessage]; | ||
| }); | ||
| this.lastTextMessageStartId = fakeAssistantMessageId; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix YAML syntax error by quoting the changelog entry.
The URL contains special characters (brackets and parentheses) that must be quoted in YAML to avoid parsing errors.
🔎 Proposed fix
📝 Committable suggestion
🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 2-2: syntax error: expected , but found ''
(syntax)
🤖 Prompt for AI Agents