154 lines
3.8 KiB
TypeScript
154 lines
3.8 KiB
TypeScript
/**
|
|
* Message format conversion utilities for Grok CLI provider
|
|
*/
|
|
|
|
import type { GrokCliMessage, GrokCliResponse } from './types.js';
|
|
|
|
/**
|
|
* AI SDK message type (simplified interface)
|
|
*/
|
|
interface AISDKMessage {
|
|
role: string;
|
|
content:
|
|
| string
|
|
| Array<{ type: string; text?: string }>
|
|
| { text?: string; [key: string]: unknown };
|
|
}
|
|
|
|
/**
|
|
* Convert AI SDK messages to Grok CLI compatible format
|
|
* @param messages - AI SDK message array
|
|
* @returns Grok CLI compatible messages
|
|
*/
|
|
export function convertToGrokCliMessages(
|
|
messages: AISDKMessage[]
|
|
): GrokCliMessage[] {
|
|
return messages.map((message) => {
|
|
// Handle different message content types
|
|
let content = '';
|
|
|
|
if (typeof message.content === 'string') {
|
|
content = message.content;
|
|
} else if (Array.isArray(message.content)) {
|
|
// Handle multi-part content (text and images)
|
|
content = message.content
|
|
.filter((part) => part.type === 'text')
|
|
.map((part) => part.text || '')
|
|
.join('\n');
|
|
} else if (message.content && typeof message.content === 'object') {
|
|
// Handle object content
|
|
content = message.content.text || JSON.stringify(message.content);
|
|
}
|
|
|
|
return {
|
|
role: message.role,
|
|
content: content.trim()
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Convert Grok CLI response to AI SDK format
|
|
* @param responseText - Raw response text from Grok CLI (JSONL format)
|
|
* @returns AI SDK compatible response object
|
|
*/
|
|
export function convertFromGrokCliResponse(responseText: string): {
|
|
text: string;
|
|
usage?: {
|
|
promptTokens: number;
|
|
completionTokens: number;
|
|
totalTokens: number;
|
|
};
|
|
} {
|
|
try {
|
|
// Grok CLI outputs JSONL format - each line is a separate JSON message
|
|
const lines = responseText
|
|
.trim()
|
|
.split('\n')
|
|
.filter((line) => line.trim());
|
|
|
|
// Parse each line as JSON and find assistant messages
|
|
const messages: GrokCliResponse[] = [];
|
|
for (const line of lines) {
|
|
try {
|
|
const message = JSON.parse(line) as GrokCliResponse;
|
|
messages.push(message);
|
|
} catch (parseError) {
|
|
// Skip invalid JSON lines
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Find the last assistant message
|
|
const assistantMessage = messages
|
|
.filter((msg) => msg.role === 'assistant')
|
|
.pop();
|
|
|
|
if (assistantMessage && assistantMessage.content) {
|
|
return {
|
|
text: assistantMessage.content,
|
|
usage: assistantMessage.usage
|
|
? {
|
|
promptTokens: assistantMessage.usage.prompt_tokens || 0,
|
|
completionTokens: assistantMessage.usage.completion_tokens || 0,
|
|
totalTokens: assistantMessage.usage.total_tokens || 0
|
|
}
|
|
: undefined
|
|
};
|
|
}
|
|
|
|
// Fallback: if no assistant message found, return the raw text
|
|
return {
|
|
text: responseText.trim(),
|
|
usage: undefined
|
|
};
|
|
} catch (error) {
|
|
// If parsing fails completely, treat as plain text response
|
|
return {
|
|
text: responseText.trim(),
|
|
usage: undefined
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a prompt string for Grok CLI from messages
|
|
* @param messages - AI SDK message array
|
|
* @returns Formatted prompt string
|
|
*/
|
|
export function createPromptFromMessages(messages: AISDKMessage[]): string {
|
|
const grokMessages = convertToGrokCliMessages(messages);
|
|
|
|
// Create a conversation-style prompt
|
|
const prompt = grokMessages
|
|
.map((message) => {
|
|
switch (message.role) {
|
|
case 'system':
|
|
return `System: ${message.content}`;
|
|
case 'user':
|
|
return `User: ${message.content}`;
|
|
case 'assistant':
|
|
return `Assistant: ${message.content}`;
|
|
default:
|
|
return `${message.role}: ${message.content}`;
|
|
}
|
|
})
|
|
.join('\n\n');
|
|
|
|
return prompt;
|
|
}
|
|
|
|
/**
|
|
* Escape shell arguments for safe CLI execution
|
|
* @param arg - Argument to escape
|
|
* @returns Shell-escaped argument
|
|
*/
|
|
export function escapeShellArg(arg: string | unknown): string {
|
|
if (typeof arg !== 'string') {
|
|
arg = String(arg);
|
|
}
|
|
|
|
// Replace single quotes with '\''
|
|
return "'" + (arg as string).replace(/'/g, "'\\''") + "'";
|
|
}
|