@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
187 lines (172 loc) • 5.83 kB
text/typescript
import { describe, expect, it } from 'vitest';
import type { PipelineContext } from '../../types';
import { ToolMessageReorder } from '../ToolMessageReorder';
const createContext = (messages: any[]): PipelineContext => ({
initialState: { messages: [] } as any,
messages,
metadata: { model: 'gpt-4', maxTokens: 4096 },
isAborted: false,
});
describe('ToolMessageReorder', () => {
it('should place tool messages right after their assistant calls and drop invalid tools', async () => {
const proc = new ToolMessageReorder();
const messages = [
{ id: 'u1', role: 'user', content: 'hi' },
{
id: 'a1',
role: 'assistant',
content: 'calling',
tool_calls: [
{ id: 'call_1', type: 'function', function: { name: 'test', arguments: '{}' } },
],
},
{ id: 't1', role: 'tool', content: '{"ok":1}', tool_call_id: 'call_1' },
{ id: 't_invalid', role: 'tool', content: '{"ok":0}' },
];
const ctx = createContext(messages);
const res = await proc.process(ctx);
expect(res.messages.map((m) => m.id)).toEqual(['u1', 'a1', 't1']);
});
it('should reorderToolMessages', async () => {
const proc = new ToolMessageReorder();
const messages = [
{
content: '## Tools\n\nYou can use these tools',
role: 'system',
},
{
content: '',
role: 'assistant',
tool_calls: [
{
function: {
arguments:
'{"query":"LobeChat","searchEngines":["brave","google","duckduckgo","qwant"]}',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
},
id: 'call_6xCmrOtFOyBAcqpqO1TGfw2B',
type: 'function',
},
{
function: {
arguments:
'{"query":"LobeChat","searchEngines":["brave","google","duckduckgo","qwant"]}',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
},
id: 'tool_call_nXxXHW8Z',
type: 'function',
},
],
},
{
content: '[]',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
role: 'tool',
tool_call_id: 'call_6xCmrOtFOyBAcqpqO1TGfw2B',
},
{
content: 'LobeHub 是一个专注于设计和开发现代人工智能生成内容(AIGC)工具和组件的团队。',
role: 'assistant',
},
{
content: '[]',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
role: 'tool',
tool_call_id: 'tool_call_nXxXHW8Z',
},
{
content: '[]',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
role: 'tool',
tool_call_id: 'tool_call_2f3CEKz9',
},
{
content: '### LobeHub 智能AI聚合神器\n\nLobeHub 是一个强大的AI聚合平台',
role: 'assistant',
},
];
const ctx = createContext(messages);
const output = await proc.process(ctx);
expect(output.messages).toEqual([
{
content: '## Tools\n\nYou can use these tools',
role: 'system',
},
{
content: '',
role: 'assistant',
tool_calls: [
{
function: {
arguments:
'{"query":"LobeChat","searchEngines":["brave","google","duckduckgo","qwant"]}',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
},
id: 'call_6xCmrOtFOyBAcqpqO1TGfw2B',
type: 'function',
},
{
function: {
arguments:
'{"query":"LobeChat","searchEngines":["brave","google","duckduckgo","qwant"]}',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
},
id: 'tool_call_nXxXHW8Z',
type: 'function',
},
],
},
{
content: '[]',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
role: 'tool',
tool_call_id: 'call_6xCmrOtFOyBAcqpqO1TGfw2B',
},
{
content: '[]',
name: 'lobe-web-browsing____searchWithSearXNG____builtin',
role: 'tool',
tool_call_id: 'tool_call_nXxXHW8Z',
},
{
content: 'LobeHub 是一个专注于设计和开发现代人工智能生成内容(AIGC)工具和组件的团队。',
role: 'assistant',
},
{
content: '### LobeHub 智能AI聚合神器\n\nLobeHub 是一个强大的AI聚合平台',
role: 'assistant',
},
]);
});
it('should correctly reorder when a tool message appears before the assistant message', async () => {
const messages = [
{
role: 'system',
content: 'System message',
},
{
role: 'tool',
tool_call_id: 'tool_call_1',
name: 'test-plugin____testApi',
content: 'Tool result',
},
{
role: 'assistant',
content: '',
tool_calls: [
{ id: 'tool_call_1', type: 'function', function: { name: 'testApi', arguments: '{}' } },
],
},
];
const proc = new ToolMessageReorder();
const ctx = createContext(messages);
const { messages: output } = await proc.process(ctx);
// Verify reordering logic works and covers line 688 hasPushed check
// In this test, tool messages are duplicated but the second occurrence is skipped
expect(output.length).toBe(4); // Original has 3, assistant will add corresponding tool message again
expect(output[0].role).toBe('system');
expect(output[1].role).toBe('tool');
expect(output[2].role).toBe('assistant');
expect(output[3].role).toBe('tool'); // Tool message added by assistant's tool_calls
});
});