UNPKG

@nanocollective/nanocoder

Version:

A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter

64 lines 2.67 kB
import { getLogger } from '../../utils/logging/index.js'; import { isEmptyAssistantMessage } from '../converters/message-converter.js'; /** * Creates the onStepFinish callback for AI SDK generateText * Since tools have no execute functions, this only handles logging. */ export function createOnStepFinishHandler(_callbacks) { const logger = getLogger(); return step => { // Log tool call steps (no results since execute is stripped) if (step.toolCalls && step.toolCalls.length > 0) { logger.trace('AI SDK tool step', { stepType: 'tool_call', toolCount: step.toolCalls.length, }); } }; } /** * Creates the prepareStep callback for AI SDK generateText * This filters out empty assistant messages and orphaned tool results */ export function createPrepareStepHandler() { const logger = getLogger(); return ({ messages }) => { // Filter out empty assistant messages that would cause API errors // "Assistant message must have either content or tool_calls" // Also filter out orphaned tool messages that follow empty assistant messages const filteredMessages = []; const indicesToSkip = new Set(); // First pass: identify empty assistant messages and their orphaned tool results for (let i = 0; i < messages.length; i++) { if (isEmptyAssistantMessage(messages[i])) { indicesToSkip.add(i); // Mark any immediately following tool messages as orphaned let j = i + 1; while (j < messages.length && messages[j].role === 'tool') { indicesToSkip.add(j); j++; } } } // Second pass: build filtered array for (let i = 0; i < messages.length; i++) { if (!indicesToSkip.has(i)) { filteredMessages.push(messages[i]); } } // Log message filtering if (filteredMessages.length !== messages.length) { logger.debug('Filtered empty assistant messages and orphaned tool results', { originalCount: messages.length, filteredCount: filteredMessages.length, removedCount: messages.length - filteredMessages.length, }); } // Return filtered messages if any were removed, otherwise no changes if (filteredMessages.length !== messages.length) { return { messages: filteredMessages }; } return {}; // No modifications needed }; } //# sourceMappingURL=streaming-handler.js.map