mirror of
https://github.com/OpenBankProject/API-Explorer-II.git
synced 2026-02-06 10:47:04 +00:00
fix tool messages not being found by ID
This commit is contained in:
parent
b192085aa3
commit
69c629c564
@ -25,7 +25,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import type { OpeyMessage, ChatStreamInput, RawOpeyMessage, OpeyToolCall, AssistantMessage } from '@/models/MessageModel'
|
||||
import type { OpeyMessage, ChatStreamInput, RawOpeyMessage, OpeyToolCall, AssistantMessage, UserMessage } from '@/models/MessageModel'
|
||||
import type { Chat } from '@/models/ChatModel'
|
||||
import { getobpConsent } from '@/obp/common-functions'
|
||||
import { defineStore } from 'pinia'
|
||||
@ -102,7 +102,10 @@ export const useChat = defineStore('chat', {
|
||||
for (const message of allMessages) {
|
||||
if (message.role === 'assistant') {
|
||||
const assistantMessage = message as AssistantMessage
|
||||
return assistantMessage.toolCalls.find(tc => tc.toolCall.id === toolCallId)
|
||||
const toolCallMatch = assistantMessage.toolCalls.find(tc => tc.toolCall.id === toolCallId)
|
||||
if (toolCallMatch) {
|
||||
return toolCallMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +121,7 @@ export const useChat = defineStore('chat', {
|
||||
*
|
||||
* @param message - The message to add to the chat
|
||||
*/
|
||||
async addMessage(message: OpeyMessage): Promise<void> {
|
||||
async addMessage(message: AssistantMessage | UserMessage): Promise<void> {
|
||||
|
||||
const existingMessage = this.messages.find(m => m.id === message.id);
|
||||
if (existingMessage) {
|
||||
@ -273,7 +276,7 @@ export const useChat = defineStore('chat', {
|
||||
if (data.type === 'tool') {
|
||||
const toolCallId = content.tool_call_id;
|
||||
if (!toolCallId) {
|
||||
throw new Error('Tool call ID not found in tool message');
|
||||
throw new Error('Tool call ID not found');
|
||||
}
|
||||
|
||||
console.log("Tool Message: ", toolCallId)
|
||||
@ -281,7 +284,7 @@ export const useChat = defineStore('chat', {
|
||||
// get the tool call that the message refers to
|
||||
const toolMessage = this.getToolCallById(toolCallId);
|
||||
if (!toolMessage) {
|
||||
throw new Error('Tool call for ID not found in messages');
|
||||
throw new Error('Tool call for this ID not found in messages');
|
||||
}
|
||||
|
||||
// Update the tool message with the content
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// Tesing the Pinia chat store in src/stores/chat.ts
|
||||
import type { OpeyMessage, ToolMessage } from '@/models/MessageModel'
|
||||
import type { AssistantMessage, OpeyMessage, OpeyToolCall, } from '@/models/MessageModel'
|
||||
import { ToolCall } from '@langchain/core/messages'
|
||||
import { useChat } from '@/stores/chat'
|
||||
import { beforeEach, describe, it, expect, vi } from 'vitest'
|
||||
@ -176,45 +176,7 @@ describe('Chat Store _proccessOpeyStream', () => {
|
||||
.toThrow('Stream closed by server')
|
||||
})
|
||||
|
||||
it('should be able a chunk with type: message and a tool call in the body', async () => {
|
||||
// create a mock stream
|
||||
const mockStream = new ReadableStream<Uint8Array>({
|
||||
start(controller) {
|
||||
controller.enqueue(new TextEncoder().encode(`data: {"type": "message", "content": {"type": "ai", "content": "", "tool_calls": [{"name": "retrieve_glossary", "args": {"question": "hre"}, "id": "call_XsmUpPIeS81l9MYpieBZtr4w", "type": "tool_call"}], "tool_approval_request": false, "tool_call_id": null, "run_id": "d0c2bcbe-62f7-464b-8564-bf9263939fe1", "original": {"type": "ai", "data": {"content": "", "additional_kwargs": {"tool_calls": [{"index": 0, "id": "call_XsmUpPIeS81l9MYpieBZtr4w", "function": {"arguments": "{\\"question\\":\\"hre\\"}", "name": "retrieve_glossary"}, "type": "function"}]}, "response_metadata": {"finish_reason": "tool_calls", "model_name": "gpt-4o-2024-08-06", "system_fingerprint": "fp_eb9dce56a8"}, "type": "ai", "name": null, "id": "run-5bb065b9-440d-4678-bbdb-cd6de94a78d3", "example": false, "tool_calls": [{"name": "retrieve_glossary", "args": {"question": "hre"}, "id": "call_XsmUpPIeS81l9MYpieBZtr4w", "type": "tool_call"}], "invalid_tool_calls": [], "usage_metadata": null}}}}\n`));
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
|
||||
// mock the fetch function
|
||||
global.fetch = vi.fn(() =>
|
||||
Promise.resolve(new Response(mockStream, {
|
||||
headers: { 'content-type': 'text/event-stream' },
|
||||
status: 200,
|
||||
}))
|
||||
);
|
||||
|
||||
await chatStore._processOpeyStream(mockStream)
|
||||
|
||||
expect(chatStore.messages).toHaveLength(1)
|
||||
|
||||
const toolMessage: ToolMessage = chatStore.messages[0] as ToolMessage
|
||||
|
||||
expect(toolMessage.awaitingApproval).toBe(false)
|
||||
expect(toolMessage.toolCall).toBeTypeOf('object')
|
||||
expect(toolMessage.pending).toBe(true)
|
||||
// Instead of checking instance directly, verify the object has the expected properties
|
||||
expect(toolMessage.toolCall).toEqual(expect.objectContaining({
|
||||
name: 'retrieve_glossary',
|
||||
args: expect.objectContaining({
|
||||
question: 'hre'
|
||||
}),
|
||||
id: 'call_XsmUpPIeS81l9MYpieBZtr4w',
|
||||
type: 'tool_call'
|
||||
}))
|
||||
expect(toolMessage.content).toBe('')
|
||||
})
|
||||
|
||||
it('should associate tool call with current assistant message', async () => {
|
||||
it('should be able to handle a chunk with type: message and a tool call in the body', async () => {
|
||||
// create a mock stream
|
||||
const mockStream = new ReadableStream<Uint8Array>({
|
||||
start(controller) {
|
||||
@ -235,16 +197,27 @@ describe('Chat Store _proccessOpeyStream', () => {
|
||||
id: '123',
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
toolCalls: []
|
||||
}
|
||||
|
||||
await chatStore._processOpeyStream(mockStream)
|
||||
|
||||
expect(chatStore.messages).toHaveLength(1)
|
||||
|
||||
const toolMessage: ToolMessage = chatStore.messages[0] as ToolMessage
|
||||
for (const toolCall of chatStore.currentAssistantMessage.toolCalls) {
|
||||
expect(toolCall.status).toBe('pending')
|
||||
expect(toolCall.toolCall).toBeDefined()
|
||||
expect(toolCall.toolCall).toEqual(expect.objectContaining({
|
||||
id: 'call_XsmUpPIeS81l9MYpieBZtr4w',
|
||||
type: 'tool_call',
|
||||
args: expect.objectContaining({
|
||||
question: 'hre'
|
||||
}),
|
||||
name: 'retrieve_glossary'
|
||||
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
expect(chatStore.currentAssistantMessage.toolCalls).toBeDefined()
|
||||
expect(chatStore.currentAssistantMessage.toolCalls).toContain(toolMessage.toolCall)
|
||||
})
|
||||
|
||||
it('should throw an error when the chunk is not valid json', async () => {
|
||||
@ -308,6 +281,7 @@ describe('Chat Store _proccessOpeyStream', () => {
|
||||
id: '456',
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
toolCalls: []
|
||||
}
|
||||
|
||||
// Push assistant message to the messages list as this is what we do in the ChatWidget to visualise token streaming
|
||||
@ -322,6 +296,8 @@ describe('Chat Store _proccessOpeyStream', () => {
|
||||
id: '456',
|
||||
role: 'assistant',
|
||||
content: mockAsisstantMessage,
|
||||
loading: false,
|
||||
toolCalls: []
|
||||
})
|
||||
|
||||
|
||||
@ -357,6 +333,7 @@ describe('Chat Store _proccessOpeyStream', () => {
|
||||
id: '456',
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
toolCalls: []
|
||||
}
|
||||
|
||||
// Push assistant message to the messages list as this is what we do in the ChatWidget to visualise token streaming
|
||||
@ -370,3 +347,133 @@ describe('Chat Store _proccessOpeyStream', () => {
|
||||
expect(hasUniqueValues(chatStore.messages)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getToolCallById', () => {
|
||||
let chatStore: ReturnType<typeof useChat>
|
||||
|
||||
beforeEach(() => {
|
||||
// Set the active Pinia store
|
||||
setActivePinia(createPinia())
|
||||
chatStore = useChat()
|
||||
})
|
||||
|
||||
it('should return the correct tool call', () => {
|
||||
const toolCall: OpeyToolCall = {
|
||||
status: 'pending',
|
||||
toolCall: {
|
||||
id: '123',
|
||||
type: 'tool_call',
|
||||
name: 'test',
|
||||
args: {
|
||||
question: 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chatStore.currentAssistantMessage = {
|
||||
id: '456',
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
toolCalls: [toolCall]
|
||||
}
|
||||
|
||||
const result = chatStore.getToolCallById('123')
|
||||
|
||||
expect(result).toEqual(toolCall)
|
||||
})
|
||||
|
||||
it('should return undefined if the tool call is not found', () => {
|
||||
const toolCall: OpeyToolCall = {
|
||||
status: 'pending',
|
||||
toolCall: {
|
||||
id: '123',
|
||||
type: 'tool_call',
|
||||
name: 'test',
|
||||
args: {
|
||||
question: 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chatStore.currentAssistantMessage = {
|
||||
id: '456',
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
toolCalls: [toolCall]
|
||||
}
|
||||
|
||||
const result = chatStore.getToolCallById('45asdfasdf6')
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should be able to get a tool call buried in the messages list', () => {
|
||||
const toolCall: OpeyToolCall = {
|
||||
status: 'pending',
|
||||
toolCall: {
|
||||
id: '151255',
|
||||
type: 'tool_call',
|
||||
name: 'test',
|
||||
args: {
|
||||
question: 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chatStore.addMessage({
|
||||
id: '123',
|
||||
role: 'user',
|
||||
content: 'hello',
|
||||
isToolCallApproval: false
|
||||
})
|
||||
|
||||
chatStore.addMessage({
|
||||
id: '420yy3',
|
||||
role: 'assistant',
|
||||
content: 'test',
|
||||
toolCalls: [toolCall]
|
||||
})
|
||||
|
||||
const result = chatStore.getToolCallById('151255')
|
||||
|
||||
expect(result).toEqual(toolCall)
|
||||
})
|
||||
|
||||
it('should be able to get a tool call buried DEEP in the messages list', () => {
|
||||
|
||||
let toolCall: OpeyToolCall
|
||||
|
||||
for (let i=0; i<6; i++) {
|
||||
|
||||
chatStore.addMessage({
|
||||
id: `user_${i}`,
|
||||
role: 'user',
|
||||
content: 'hello',
|
||||
isToolCallApproval: false
|
||||
})
|
||||
|
||||
toolCall = {
|
||||
status: 'pending',
|
||||
toolCall: {
|
||||
id: `tool_${i}`,
|
||||
type: 'tool_call',
|
||||
name: 'test',
|
||||
args: {
|
||||
question: 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chatStore.addMessage({
|
||||
id: `assistant_${i}`,
|
||||
role: 'assistant',
|
||||
content: 'test',
|
||||
toolCalls: [toolCall]
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const result = chatStore.getToolCallById('tool_3')
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
})
|
||||
@ -33,7 +33,7 @@ export default defineConfig({
|
||||
environment: 'happy-dom', // Simulates a browser environment
|
||||
exclude:[
|
||||
...configDefaults.exclude,
|
||||
//'**/backend-tests/*'
|
||||
'**/integration/*'
|
||||
],
|
||||
pool: "vmThreads",
|
||||
deps: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user