buster/packages/ai/src/tools/planning-thinking-tools/sequential-thinking-tool-st...

175 lines
5.9 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { validateArrayAccess } from '../../utils/validation-helpers';
import { parseStreamingArgs } from './sequential-thinking-tool';
describe('Sequential Thinking Tool Streaming Parser', () => {
test('should return null for empty or invalid input', () => {
expect(parseStreamingArgs('')).toBeNull();
expect(parseStreamingArgs('{')).toBeNull();
expect(parseStreamingArgs('invalid json')).toBeNull();
expect(parseStreamingArgs('{"other_field":')).toBeNull();
});
test('should parse complete JSON with all fields', () => {
const completeJson = JSON.stringify({
thought: 'I need to analyze this step by step',
nextThoughtNeeded: true,
thoughtNumber: 1,
});
const result = parseStreamingArgs(completeJson);
expect(result).toEqual({
thought: 'I need to analyze this step by step',
nextThoughtNeeded: true,
thoughtNumber: 1,
});
});
test('should extract partial thought as it builds incrementally', () => {
// Simulate the streaming chunks building up a thought
const chunks = [
'{"thought"',
'{"thought":',
'{"thought": "',
'{"thought": "I',
'{"thought": "I need',
'{"thought": "I need to',
'{"thought": "I need to analyze',
'{"thought": "I need to analyze this",',
'{"thought": "I need to analyze this", "nextThoughtNeeded"',
'{"thought": "I need to analyze this", "nextThoughtNeeded":',
'{"thought": "I need to analyze this", "nextThoughtNeeded": true',
'{"thought": "I need to analyze this", "nextThoughtNeeded": true,',
'{"thought": "I need to analyze this", "nextThoughtNeeded": true, "thoughtNumber": 1',
];
// Test incremental building
expect(parseStreamingArgs(validateArrayAccess(chunks, 0, 'test chunks'))).toBeNull(); // No colon yet
expect(parseStreamingArgs(validateArrayAccess(chunks, 1, 'test chunks'))).toBeNull(); // No opening quote yet
expect(parseStreamingArgs(validateArrayAccess(chunks, 2, 'test chunks'))).toEqual({
thought: '',
}); // Empty string
expect(parseStreamingArgs(validateArrayAccess(chunks, 3, 'test chunks'))).toEqual({
thought: 'I',
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 4, 'test chunks'))).toEqual({
thought: 'I need',
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 5, 'test chunks'))).toEqual({
thought: 'I need to',
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 6, 'test chunks'))).toEqual({
thought: 'I need to analyze',
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 7, 'test chunks'))).toEqual({
thought: 'I need to analyze this',
});
// As more fields are added
expect(parseStreamingArgs(validateArrayAccess(chunks, 8, 'test chunks'))).toEqual({
thought: 'I need to analyze this',
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 9, 'test chunks'))).toEqual({
thought: 'I need to analyze this',
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 10, 'test chunks'))).toEqual({
thought: 'I need to analyze this',
nextThoughtNeeded: true,
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 11, 'test chunks'))).toEqual({
thought: 'I need to analyze this',
nextThoughtNeeded: true,
});
expect(parseStreamingArgs(validateArrayAccess(chunks, 12, 'test chunks'))).toEqual({
thought: 'I need to analyze this',
nextThoughtNeeded: true,
thoughtNumber: 1,
});
});
test('should handle boolean fields correctly', () => {
const withBooleans = '{"nextThoughtNeeded": true';
const result = parseStreamingArgs(withBooleans);
expect(result).toEqual({
nextThoughtNeeded: true,
});
});
test('should handle number fields correctly', () => {
const withNumbers = '{"thoughtNumber": 3';
const result = parseStreamingArgs(withNumbers);
expect(result).toEqual({
thoughtNumber: 3,
});
});
test('should handle escaped quotes in thought', () => {
const withEscapedQuotes = '{"thought": "This is a \\"quoted\\" text"';
const result = parseStreamingArgs(withEscapedQuotes);
expect(result).toEqual({
thought: 'This is a "quoted" text',
});
});
test('should handle mixed field types', () => {
const mixedFields =
'{"thought": "Step 1 analysis", "thoughtNumber": 1, "nextThoughtNeeded": true';
const result = parseStreamingArgs(mixedFields);
expect(result).toEqual({
thought: 'Step 1 analysis',
thoughtNumber: 1,
nextThoughtNeeded: true,
});
});
test('should handle whitespace variations', () => {
const withWhitespace =
'{ "thought" : "Test" , "thoughtNumber" : 1 , "nextThoughtNeeded" : true';
const result = parseStreamingArgs(withWhitespace);
expect(result).toEqual({
thought: 'Test',
thoughtNumber: 1,
nextThoughtNeeded: true,
});
});
test('should handle complex thought with newlines and special characters', () => {
const complexThought =
'{"thought": "Step 1:\\nAnalyze the problem\\n- Check assumptions\\n- Review data"';
const result = parseStreamingArgs(complexThought);
expect(result).toEqual({
thought: 'Step 1:\\nAnalyze the problem\\n- Check assumptions\\n- Review data',
});
});
test('should return null if no recognized fields are present', () => {
const withoutKnownFields = '{"unknown_field": "value", "other": 123';
const result = parseStreamingArgs(withoutKnownFields);
expect(result).toBeNull();
});
test('should handle complete JSON correctly', () => {
const completeJson = JSON.stringify({
thought: 'Complete thought',
nextThoughtNeeded: false,
thoughtNumber: 5,
});
const result = parseStreamingArgs(completeJson);
expect(result).toEqual({
thought: 'Complete thought',
nextThoughtNeeded: false,
thoughtNumber: 5,
});
});
});