mirror of https://github.com/buster-so/buster.git
sequential thinking tie off the request.
This commit is contained in:
parent
4c042a34fa
commit
95b67529ad
|
@ -343,4 +343,51 @@ describe('extract-values-search-step integration', () => {
|
||||||
expect(Array.isArray(result.values)).toBe(true);
|
expect(Array.isArray(result.values)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not create valuesMessage with empty content when search returns no results', async () => {
|
||||||
|
const messages: ModelMessage[] = [
|
||||||
|
{ role: 'user', content: 'Show me sales for Red Bull' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Test with a dataSourceId that would trigger search but return empty results
|
||||||
|
const params = {
|
||||||
|
messages,
|
||||||
|
dataSourceId: 'test-datasource-id',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await runExtractValuesAndSearchStep(params);
|
||||||
|
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result.values).toBeDefined();
|
||||||
|
|
||||||
|
// If valuesMessage exists, it should have non-empty content
|
||||||
|
if (result.valuesMessage) {
|
||||||
|
expect(result.valuesMessage.content).toBeTruthy();
|
||||||
|
expect(typeof result.valuesMessage.content).toBe('string');
|
||||||
|
expect((result.valuesMessage.content as string).length).toBeGreaterThan(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not create valuesMessage when extracted values exist but search results are empty', async () => {
|
||||||
|
const messages: ModelMessage[] = [
|
||||||
|
{ role: 'user', content: 'Show me Nike and Adidas products' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
messages,
|
||||||
|
dataSourceId: 'test-datasource-id',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await runExtractValuesAndSearchStep(params);
|
||||||
|
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(result.values).toBeDefined();
|
||||||
|
|
||||||
|
// Verify that if we have values but no search results, valuesMessage is undefined
|
||||||
|
// This prevents empty string messages from being created
|
||||||
|
if (result.values.length > 0 && result.valuesMessage) {
|
||||||
|
expect(result.valuesMessage.content).toBeTruthy();
|
||||||
|
expect((result.valuesMessage.content as string).trim()).not.toBe('');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -185,7 +185,7 @@ export async function runExtractValuesAndSearchStep(
|
||||||
return {
|
return {
|
||||||
values: extractedValues,
|
values: extractedValues,
|
||||||
valuesMessage:
|
valuesMessage:
|
||||||
extractedValues.length > 0
|
extractedValues.length > 0 && storedValuesResult.searchResults
|
||||||
? {
|
? {
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: storedValuesResult.searchResults,
|
content: storedValuesResult.searchResults,
|
||||||
|
|
|
@ -12,14 +12,14 @@ import type { SequentialThinkingState } from '../sequential-thinking-tool';
|
||||||
*/
|
*/
|
||||||
export function createSequentialThinkingReasoningMessage(
|
export function createSequentialThinkingReasoningMessage(
|
||||||
sequentialThinkingState: SequentialThinkingState,
|
sequentialThinkingState: SequentialThinkingState,
|
||||||
toolCallId?: string,
|
toolCallId: string,
|
||||||
status: ChatMessageReasoning_status = 'loading'
|
status: ChatMessageReasoning_status = 'loading'
|
||||||
): ChatMessageReasoningMessage_Text | null {
|
): ChatMessageReasoningMessage_Text {
|
||||||
// Use entry_id from state or fallback to provided toolCallId
|
// Use entry_id from state or fallback to provided toolCallId
|
||||||
const id = toolCallId;
|
const id = toolCallId;
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return null;
|
throw new Error('Tool call ID is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine title based on status
|
// Determine title based on status
|
||||||
|
@ -49,11 +49,11 @@ export function createSequentialThinkingReasoningMessage(
|
||||||
export function createSequentialThinkingRawLlmMessageEntry(
|
export function createSequentialThinkingRawLlmMessageEntry(
|
||||||
sequentialThinkingState: SequentialThinkingState,
|
sequentialThinkingState: SequentialThinkingState,
|
||||||
toolCallId?: string
|
toolCallId?: string
|
||||||
): ModelMessage | null {
|
): ModelMessage {
|
||||||
const id = toolCallId;
|
const id = toolCallId;
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return null;
|
throw new Error('Tool call ID is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the input object with available state
|
// Build the input object with available state
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { updateMessageEntries } from '@buster/database';
|
import { type UpdateMessageEntriesParams, updateMessageEntries } from '@buster/database';
|
||||||
import { wrapTraced } from 'braintrust';
|
import { wrapTraced } from 'braintrust';
|
||||||
import { normalizeEscapedText } from '../../../utils/streaming/escape-normalizer';
|
import { normalizeEscapedText } from '../../../utils/streaming/escape-normalizer';
|
||||||
import { createRawToolResultEntry } from '../../shared/create-raw-llm-tool-result-entry';
|
import { createRawToolResultEntry } from '../../shared/create-raw-llm-tool-result-entry';
|
||||||
|
@ -16,24 +16,42 @@ import {
|
||||||
|
|
||||||
// Process sequential thinking execution
|
// Process sequential thinking execution
|
||||||
async function processSequentialThinking(
|
async function processSequentialThinking(
|
||||||
toolCallId: string,
|
state: SequentialThinkingState,
|
||||||
messageId: string
|
context: SequentialThinkingContext
|
||||||
): Promise<SequentialThinkingOutput> {
|
): Promise<SequentialThinkingOutput> {
|
||||||
const output: SequentialThinkingOutput = {
|
const output: SequentialThinkingOutput = {
|
||||||
success: true,
|
success: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const entries: UpdateMessageEntriesParams = {
|
||||||
|
messageId: context.messageId,
|
||||||
|
reasoningMessages: [],
|
||||||
|
rawLlmMessages: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const reasoningEntry = createSequentialThinkingReasoningMessage(
|
||||||
|
state,
|
||||||
|
context.messageId,
|
||||||
|
'completed'
|
||||||
|
);
|
||||||
|
const rawLlmMessage = createSequentialThinkingRawLlmMessageEntry(state, context.messageId);
|
||||||
|
|
||||||
const rawToolResultEntry = createRawToolResultEntry(
|
const rawToolResultEntry = createRawToolResultEntry(
|
||||||
toolCallId,
|
context.messageId,
|
||||||
SEQUENTIAL_THINKING_TOOL_NAME,
|
SEQUENTIAL_THINKING_TOOL_NAME,
|
||||||
output
|
output
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (reasoningEntry) {
|
||||||
|
entries.reasoningMessages = [reasoningEntry];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawLlmMessage) {
|
||||||
|
entries.rawLlmMessages = [rawLlmMessage, rawToolResultEntry];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateMessageEntries({
|
await updateMessageEntries(entries);
|
||||||
messageId,
|
|
||||||
rawLlmMessages: [rawToolResultEntry],
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[sequential-thinking] Error updating message entries:', error);
|
console.error('[sequential-thinking] Error updating message entries:', error);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +72,7 @@ export function createSequentialThinkingExecute(
|
||||||
throw new Error('Tool call ID is required');
|
throw new Error('Tool call ID is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
return await processSequentialThinking(state.toolCallId, context.messageId);
|
return await processSequentialThinking(state, context);
|
||||||
},
|
},
|
||||||
{ name: SEQUENTIAL_THINKING_TOOL_NAME }
|
{ name: SEQUENTIAL_THINKING_TOOL_NAME }
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue