@aj-archipelago/cortex
Version:
Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.
1,393 lines (1,203 loc) • 38.5 kB
JavaScript
// grokVisionPlugin.test.js
// This file contains direct plugin tests for GrokVisionPlugin (non-connecting tests)
import test from 'ava';
import GrokVisionPlugin from '../../../server/plugins/grokVisionPlugin.js';
import { safeJsonParse } from '../../../server/plugins/grokVisionPlugin.js';
test('should create GrokVisionPlugin instance', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
t.true(plugin instanceof GrokVisionPlugin);
t.is(plugin.modelName, 'xai-grok-3');
t.true(plugin.isMultiModal);
});
test('should handle Grok-specific parameters', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const parameters = {
search_parameters: '{"mode": "auto"}'
};
const requestParams = await plugin.getRequestParameters('test text', parameters, {});
t.truthy(requestParams.search_parameters);
t.is(requestParams.search_parameters.mode, 'auto');
// Vision parameters are handled in message content, not as top-level parameters
});
test('should handle all Live Search parameters correctly', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test comprehensive Live Search parameters as JSON string
const parameters = {
search_parameters: JSON.stringify({
mode: 'on',
return_citations: true,
from_date: '2024-01-01',
to_date: '2024-12-31',
max_search_results: 15,
sources: [
{ type: 'web', country: 'US', excluded_websites: ['wikipedia.org'] },
{ type: 'x', included_x_handles: ['xai'], post_favorite_count: 1000 },
{ type: 'news', safe_search: false },
{ type: 'rss', links: ['https://status.x.ai/feed.xml'] }
]
})
};
const requestParams = await plugin.getRequestParameters('Search for latest tech news', parameters, {});
// Verify all search_parameters are set correctly
t.truthy(requestParams.search_parameters, 'search_parameters should be set');
t.is(requestParams.search_parameters.mode, 'on', 'search mode should be on');
t.true(requestParams.search_parameters.return_citations, 'return_citations should be true');
t.is(requestParams.search_parameters.from_date, '2024-01-01', 'from_date should be set');
t.is(requestParams.search_parameters.to_date, '2024-12-31', 'to_date should be set');
t.is(requestParams.search_parameters.max_search_results, 15, 'max_search_results should be 15');
t.truthy(requestParams.search_parameters.sources, 'sources should be set');
t.is(requestParams.search_parameters.sources.length, 4, 'should have 4 sources');
// Verify web source
const webSource = requestParams.search_parameters.sources.find(s => s.type === 'web');
t.truthy(webSource, 'web source should exist');
t.is(webSource.country, 'US', 'web source country should be US');
t.deepEqual(webSource.excluded_websites, ['wikipedia.org'], 'web source excluded_websites should be set');
// Verify X source
const xSource = requestParams.search_parameters.sources.find(s => s.type === 'x');
t.truthy(xSource, 'x source should exist');
t.deepEqual(xSource.included_x_handles, ['xai'], 'x source included_x_handles should be set');
t.is(xSource.post_favorite_count, 1000, 'x source post_favorite_count should be 1000');
// Verify news source
const newsSource = requestParams.search_parameters.sources.find(s => s.type === 'news');
t.truthy(newsSource, 'news source should exist');
t.false(newsSource.safe_search, 'news source safe_search should be false');
// Verify RSS source
const rssSource = requestParams.search_parameters.sources.find(s => s.type === 'rss');
t.truthy(rssSource, 'rss source should exist');
t.deepEqual(rssSource.links, ['https://status.x.ai/feed.xml'], 'rss source links should be set');
});
test('should handle individual source parameters correctly', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test web source with allowed_websites
const webParameters = {
search_parameters: JSON.stringify({
mode: 'auto',
sources: [{ type: 'web', allowed_websites: ['x.ai', 'github.com'] }]
})
};
const webRequestParams = await plugin.getRequestParameters('Search xAI website', webParameters, {});
const webSource = webRequestParams.search_parameters.sources[0];
t.deepEqual(webSource.allowed_websites, ['x.ai', 'github.com'], 'web source allowed_websites should be set');
// Test X source with excluded_handles and view count
const xParameters = {
search_parameters: JSON.stringify({
mode: 'auto',
sources: [{
type: 'x',
excluded_x_handles: ['spam_account'],
post_view_count: 50000
}]
})
};
const xRequestParams = await plugin.getRequestParameters('Search X posts', xParameters, {});
const xSource = xRequestParams.search_parameters.sources[0];
t.deepEqual(xSource.excluded_x_handles, ['spam_account'], 'x source excluded_x_handles should be set');
t.is(xSource.post_view_count, 50000, 'x source post_view_count should be set');
});
test('should handle date range parameters correctly', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test with only from_date
const fromDateParameters = {
search_parameters: JSON.stringify({
mode: 'auto',
from_date: '2024-06-01'
})
};
const fromDateRequestParams = await plugin.getRequestParameters('Search recent news', fromDateParameters, {});
t.is(fromDateRequestParams.search_parameters.from_date, '2024-06-01', 'from_date should be set');
t.is(fromDateRequestParams.search_parameters.to_date, undefined, 'to_date should not be set');
// Test with only to_date
const toDateParameters = {
search_parameters: JSON.stringify({
mode: 'auto',
to_date: '2024-12-31'
})
};
const toDateRequestParams = await plugin.getRequestParameters('Search historical data', toDateParameters, {});
t.is(toDateRequestParams.search_parameters.to_date, '2024-12-31', 'to_date should be set');
t.is(toDateRequestParams.search_parameters.from_date, undefined, 'from_date should not be set');
// Test with both dates
const bothDatesParameters = {
search_parameters: JSON.stringify({
mode: 'auto',
from_date: '2024-01-01',
to_date: '2024-06-30'
})
};
const bothDatesRequestParams = await plugin.getRequestParameters('Search specific period', bothDatesParameters, {});
t.is(bothDatesRequestParams.search_parameters.from_date, '2024-01-01', 'from_date should be set');
t.is(bothDatesRequestParams.search_parameters.to_date, '2024-06-30', 'to_date should be set');
});
test('should handle empty search_parameters correctly', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test with empty search_parameters (should not be set)
const emptyParameters = {};
const emptyRequestParams = await plugin.getRequestParameters('Search with defaults', emptyParameters, {});
t.is(emptyRequestParams.search_parameters, undefined, 'search_parameters should not be set when not provided');
// Test with empty JSON string
const emptyJsonParameters = {
search_parameters: '{}'
};
const emptyJsonRequestParams = await plugin.getRequestParameters('Search with empty json', emptyJsonParameters, {});
t.is(emptyJsonRequestParams.search_parameters, undefined, 'search_parameters should not be set when empty object provided');
});
// Note: grok_live_search pathway test removed as the pathway file does not exist yet
test('should handle X.AI vision message structure correctly', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test vision message with URL image
const visionMessages = [
{
role: 'user',
content: [
{
type: 'image_url',
image_url: {
url: 'https://example.com/image.jpg',
detail: 'high'
}
},
{
type: 'text',
text: 'What is in this image?'
}
]
}
];
const parameters = {};
const requestParams = await plugin.getRequestParameters('', parameters, {});
requestParams.messages = visionMessages;
// Verify vision message structure
t.is(requestParams.messages[0].content.length, 2, 'should have 2 content items');
t.is(requestParams.messages[0].content[0].type, 'image_url', 'first item should be image_url');
t.is(requestParams.messages[0].content[1].type, 'text', 'second item should be text');
t.is(requestParams.messages[0].content[0].image_url.detail, 'high', 'image detail should be high');
t.is(requestParams.messages[0].content[0].image_url.url, 'https://example.com/image.jpg', 'image URL should be set');
});
test('should handle X.AI vision with base64 images', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test vision message with base64 image
const base64Image = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k=';
const visionMessages = [
{
role: 'user',
content: [
{
type: 'text',
text: 'What is in this image?'
},
{
type: 'image_url',
image_url: {
url: base64Image,
detail: 'auto'
}
}
]
}
];
const parameters = {};
const requestParams = await plugin.getRequestParameters('', parameters, {});
requestParams.messages = visionMessages;
// Verify base64 image message structure
t.is(requestParams.messages[0].content.length, 2, 'should have 2 content items');
t.is(requestParams.messages[0].content[0].type, 'text', 'first item should be text');
t.is(requestParams.messages[0].content[1].type, 'image_url', 'second item should be image_url');
t.is(requestParams.messages[0].content[1].image_url.detail, 'auto', 'image detail should be auto');
t.true(requestParams.messages[0].content[1].image_url.url.startsWith('data:image/jpeg;base64,'), 'should be base64 image');
});
test('should handle X.AI vision with multiple images', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test vision message with multiple images
const visionMessages = [
{
role: 'user',
content: [
{
type: 'text',
text: 'What are in these images?'
},
{
type: 'image_url',
image_url: {
url: 'https://example.com/image1.jpg',
detail: 'high'
}
},
{
type: 'image_url',
image_url: {
url: 'https://example.com/image2.jpg',
detail: 'low'
}
},
{
type: 'text',
text: 'Compare them.'
}
]
}
];
const parameters = {};
const requestParams = await plugin.getRequestParameters('', parameters, {});
requestParams.messages = visionMessages;
// Verify multiple images message structure
t.is(requestParams.messages[0].content.length, 4, 'should have 4 content items');
t.is(requestParams.messages[0].content[0].type, 'text', 'first item should be text');
t.is(requestParams.messages[0].content[1].type, 'image_url', 'second item should be image_url');
t.is(requestParams.messages[0].content[2].type, 'image_url', 'third item should be image_url');
t.is(requestParams.messages[0].content[3].type, 'text', 'fourth item should be text');
t.is(requestParams.messages[0].content[1].image_url.detail, 'high', 'first image detail should be high');
t.is(requestParams.messages[0].content[2].image_url.detail, 'low', 'second image detail should be low');
});
test('should parse Grok response with citations', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const mockResponse = {
choices: [{
message: {
role: 'assistant',
content: 'Test response'
}
}],
citations: [
'https://example.com'
]
};
const result = plugin.parseResponse(mockResponse);
// Should return a CortexResponse object
t.is(result.output_text, 'Test response');
t.truthy(result.citations);
// Citations are created from URLs, so title is extracted from URL
t.is(result.citations[0].url, 'https://example.com');
});
test('should handle tool calls in response', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const mockResponse = {
choices: [{
message: {
role: 'assistant',
content: 'I will call a tool',
tool_calls: [
{
id: 'call_123',
type: 'function',
function: {
name: 'test_function',
arguments: '{"param": "value"}'
}
}
]
}
}]
};
const result = plugin.parseResponse(mockResponse);
t.is(result.output_text, 'I will call a tool');
t.truthy(result.toolCalls);
t.is(result.toolCalls[0].function.name, 'test_function');
});
test('should handle string response from parent', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const mockResponse = {
choices: [{
message: {
role: 'assistant',
content: 'Simple text response'
}
}]
};
const result = plugin.parseResponse(mockResponse);
// Should return a CortexResponse object for simple responses
t.is(result.output_text, 'Simple text response');
});
test('should handle basic Grok API response format', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// This matches the actual Grok API response format from your curl example
const mockResponse = {
"id": "13493401-f153-7de6-ac07-c6f6b2609b06",
"object": "chat.completion",
"created": 1753113536,
"model": "grok-3",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hi\nHello World",
"refusal": null
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 4,
"total_tokens": 32,
"prompt_tokens_details": {
"text_tokens": 28,
"audio_tokens": 0,
"image_tokens": 0,
"cached_tokens": 5
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
},
"num_sources_used": 0
},
"system_fingerprint": "fp_0d42a4eb3d"
};
const result = plugin.parseResponse(mockResponse);
// Should return a CortexResponse object
t.is(result.output_text, 'Hi\nHello World');
});
test('should parse messages with image content', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const messages = [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe this image' },
{
type: 'image_url',
image_url: {
url: 'https://example.com/image.jpg',
detail: 'auto'
}
}
]
}
];
// Mock validateImageUrl to return true
plugin.validateImageUrl = () => Promise.resolve(true);
const result = await plugin.tryParseMessages(messages);
t.is(result[0].content.length, 2);
t.is(result[0].content[0].type, 'text');
t.is(result[0].content[1].type, 'image_url');
t.is(result[0].content[1].image_url.detail, 'auto');
});
test('should handle Grok vision response with web search results', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const mockResponse = {
choices: [{
message: {
role: 'assistant',
content: 'Based on the image and web search...'
}
}],
web_search_results: [
{
title: 'Search Result',
snippet: 'Relevant information',
url: 'https://example.com'
}
]
};
const result = plugin.parseResponse(mockResponse);
// Should return a CortexResponse object
t.is(result.output_text, 'Based on the image and web search...');
t.truthy(result.searchResults);
t.is(result.searchResults[0].title, 'Search Result');
});
test('should handle streaming events with Grok-specific fields', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const event = {
data: JSON.stringify({
choices: [{
delta: {
content: 'Test content',
citations: [{ title: 'Citation', url: 'https://example.com' }],
search_queries: ['test query'],
web_search_results: [{ title: 'Result', url: 'https://example.com' }],
real_time_data: { timestamp: '2024-01-01T00:00:00Z', data: 'Real-time info' }
}
}]
})
};
const requestProgress = { data: '', progress: 0 };
const result = plugin.processStreamEvent(event, requestProgress);
// Should return the requestProgress object (calls parent implementation)
t.is(result, requestProgress);
t.is(typeof result.data, 'string');
t.is(typeof result.progress, 'number');
});
test('should handle end of stream event', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-4',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-4-0709'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const event = { data: '[DONE]' };
const requestProgress = { data: '', progress: 0 };
const result = plugin.processStreamEvent(event, requestProgress);
t.is(result.progress, 1);
});
test('should handle Live Search parameters correctly', async t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Test Live Search specific parameters
const parameters = {
search_parameters: '{"mode": "auto"}'
};
const requestParams = await plugin.getRequestParameters('Search for latest tech news', parameters, {});
// Verify search_parameters are set correctly
t.truthy(requestParams.search_parameters, 'search_parameters should be set');
t.is(requestParams.search_parameters.mode, 'auto', 'search mode should be auto');
});
test('should parse Live Search response with real-time data', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Mock response with Live Search data
const mockResponse = {
choices: [{
message: {
role: 'assistant',
content: 'Based on real-time data from X...'
}
}],
citations: [
'https://x.com/user/status/123456'
],
search_queries: ['AI trends', 'artificial intelligence 2024'],
web_search_results: [
{
title: 'Latest AI Developments',
snippet: 'Recent breakthroughs in AI technology...',
url: 'https://example.com/ai-news'
}
],
real_time_data: {
timestamp: '2024-01-01T12:00:00Z',
platform: 'X',
trending_topics: ['AI', 'Machine Learning'],
engagement_metrics: {
likes: 1000,
retweets: 500,
replies: 200
}
}
};
const result = plugin.parseResponse(mockResponse);
// Verify all Live Search response fields are parsed correctly
t.is(result.output_text, 'Based on real-time data from X...');
t.truthy(result.citations, 'Should have citations');
t.is(result.citations[0].url, 'https://x.com/user/status/123456');
t.truthy(result.searchQueries, 'Should have search queries');
t.is(result.searchQueries[0], 'AI trends');
t.truthy(result.searchResults, 'Should have web search results');
t.is(result.searchResults[0].title, 'Latest AI Developments');
t.truthy(result.realTimeData, 'Should have real-time data');
t.is(result.realTimeData.platform, 'X');
t.truthy(result.realTimeData.trending_topics, 'Should have trending topics');
});
test('should parse Live Search response with usage data', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
// Mock response with Live Search usage data
const mockResponse = {
choices: [{
message: {
role: 'assistant',
content: 'Based on live search results...'
}
}],
citations: [
'https://example.com/result1',
'https://example.com/result2'
],
usage: {
prompt_tokens: 150,
completion_tokens: 200,
total_tokens: 350,
num_sources_used: 5
}
};
const result = plugin.parseResponse(mockResponse);
// Verify response content and citations
t.is(result.output_text, 'Based on live search results...');
t.truthy(result.citations, 'Should have citations');
t.is(result.citations.length, 2, 'Should have 2 citations');
t.is(result.citations[0].url, 'https://example.com/result1');
t.is(result.citations[1].url, 'https://example.com/result2');
// Verify usage data is preserved
t.truthy(mockResponse.usage, 'Usage data should be preserved in original response');
t.is(mockResponse.usage.num_sources_used, 5, 'Should show 5 sources used');
});
test('should validate search parameters - valid parameters', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const validParams = {
mode: 'auto',
return_citations: true,
from_date: '2024-01-01',
to_date: '2024-12-31',
max_search_results: 25,
sources: [
{ type: 'web', country: 'US' },
{ type: 'x', included_x_handles: ['testuser'] },
{ type: 'news' },
{ type: 'rss', links: ['https://example.com/feed.xml'] }
]
};
t.true(plugin.validateSearchParameters(validParams));
});
test('should validate search parameters - invalid mode', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidParams = {
mode: 'invalid_mode'
};
const error = t.throws(() => plugin.validateSearchParameters(invalidParams));
t.true(error.message.includes('Invalid \'mode\' parameter'));
});
test('should validate search parameters - invalid date format', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidParams = {
from_date: '2024/01/01' // Invalid format
};
const error = t.throws(() => plugin.validateSearchParameters(invalidParams));
t.true(error.message.includes('must be in YYYY-MM-DD format'));
});
test('should validate search parameters - invalid max_search_results', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidParams = {
max_search_results: 100 // Too high
};
const error = t.throws(() => plugin.validateSearchParameters(invalidParams));
t.true(error.message.includes('must be 50 or less'));
});
test('should validate search parameters - invalid X handles count', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidParams = {
sources: [{
type: 'x',
included_x_handles: Array(11).fill('user') // Too many handles
}]
};
const error = t.throws(() => plugin.validateSearchParameters(invalidParams));
t.true(error.message.includes('can have a maximum of 10 items'));
});
test('should validate search parameters - conflicting X handles', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidParams = {
sources: [{
type: 'x',
included_x_handles: ['user1'],
excluded_x_handles: ['user2'] // Cannot specify both
}]
};
const error = t.throws(() => plugin.validateSearchParameters(invalidParams));
t.true(error.message.includes('cannot be specified simultaneously'));
});
test('should validate search parameters - invalid RSS links count', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidParams = {
sources: [{
type: 'rss',
links: ['https://feed1.xml', 'https://feed2.xml'] // Too many links
}]
};
const error = t.throws(() => plugin.validateSearchParameters(invalidParams));
t.true(error.message.includes('can only have one item'));
});
test('safeJsonParse should parse valid JSON', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const validJson = '{"key": "value", "number": 42}';
const result = safeJsonParse(validJson);
t.deepEqual(result, { key: 'value', number: 42 });
});
test('safeJsonParse should return original string for invalid JSON', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const invalidJson = '{"key": "value", "invalid": }';
const result = safeJsonParse(invalidJson);
t.is(result, invalidJson);
});
test('safeJsonParse should return non-string input as-is', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
const objectInput = { key: 'value' };
const result = safeJsonParse(objectInput);
t.is(result, objectInput);
});
test('safeJsonParse should return null/undefined as-is', t => {
const mockPathway = {
name: 'test-pathway',
temperature: 0.7,
prompt: 'Test prompt'
};
const mockModel = {
name: 'xai-grok-3',
type: 'GROK-VISION',
url: 'https://api.x.ai/v1/chat/completions',
headers: {
'Authorization': 'Bearer test-key',
'Content-Type': 'application/json'
},
params: {
model: 'grok-3-latest'
},
maxTokenLength: 131072,
maxReturnTokens: 4096
};
const plugin = new GrokVisionPlugin(mockPathway, mockModel);
t.is(safeJsonParse(null), null);
t.is(safeJsonParse(undefined), undefined);
});