UNPKG

@xynehq/jaf

Version:

Juspay Agent Framework - A purely functional agent framework with immutable state and composable tools

123 lines 5.85 kB
import { generateText, generateObject, tool, zodSchema, } from 'ai'; import { getTextContent } from '../core/types.js'; import { safeConsole } from '../utils/logger.js'; function safeParseJson(text) { try { return JSON.parse(text); } catch { return text; } } export const createAiSdkProvider = (model) => { const lm = model; return { async getCompletion(state, agent) { const system = agent.instructions(state); // Convert JAF messages to AI SDK ModelMessages using standard OpenAI format const messages = []; const toolNameById = new Map(); for (const msg of state.messages) { switch (msg.role) { case 'user': messages.push({ role: 'user', content: getTextContent(msg.content) }); break; case 'assistant': if (msg.tool_calls && msg.tool_calls.length > 0) { // Assistant message with tool calls as content parts const parts = []; const text = getTextContent(msg.content); if (text) parts.push({ type: 'text', text }); for (const tc of msg.tool_calls) { toolNameById.set(tc.id, tc.function.name); parts.push({ type: 'tool-call', toolCallId: tc.id, toolName: tc.function.name, input: safeParseJson(tc.function.arguments), }); } messages.push({ role: 'assistant', content: parts }); } else { messages.push({ role: 'assistant', content: getTextContent(msg.content) }); } break; case 'tool': { const toolCallId = msg.tool_call_id; const toolName = toolNameById.get(toolCallId) ?? 'unknown'; const parsed = safeParseJson(getTextContent(msg.content)); const output = typeof parsed === 'string' ? { type: 'text', value: parsed } : { type: 'json', value: parsed }; const content = [ { type: 'tool-result', toolCallId, toolName, output }, ]; messages.push({ role: 'tool', content }); break; } } } // Decide whether to enable tool calls or produce final structured output const lastJafMessage = state.messages[state.messages.length - 1]; const hasCompletedTools = lastJafMessage?.role === 'tool'; const toolsForAiSDK = !hasCompletedTools && agent.tools && agent.tools.length > 0 ? agent.tools.reduce((acc, jafTool) => { const toSchema = zodSchema; acc[jafTool.schema.name] = tool({ description: jafTool.schema.description, inputSchema: toSchema(jafTool.schema.parameters), }); return acc; }, {}) : undefined; const shouldGenerateObject = Boolean(agent.outputCodec) && !toolsForAiSDK; if (shouldGenerateObject) { const toSchema = zodSchema; const go = generateObject; const resultUnknown = await go({ model: lm, schema: toSchema(agent.outputCodec), system, messages, temperature: agent.modelConfig?.temperature, maxOutputTokens: agent.modelConfig?.maxTokens, }); const object = resultUnknown.object; return { message: { content: JSON.stringify(object) } }; } safeConsole.log(`[DEBUG] Tools passed to AI SDK: ${toolsForAiSDK ? Object.keys(toolsForAiSDK).length : 0} (hasCompletedTools: ${hasCompletedTools})`); try { safeConsole.log('[DEBUG] Messages being passed to AI SDK:', JSON.stringify(messages, null, 2)); const completeResponse = await generateText({ model: lm, system, messages, tools: toolsForAiSDK, temperature: agent.modelConfig?.temperature, maxOutputTokens: agent.modelConfig?.maxTokens, }); safeConsole.log('[DEBUG] AI SDK generateText response summary:', { text: completeResponse.text?.slice(0, 100), toolCallsCount: completeResponse.toolCalls?.length ?? 0, }); return { message: { content: completeResponse.text, tool_calls: completeResponse.toolCalls?.map((tc) => ({ id: tc.toolCallId, type: 'function', function: { name: tc.toolName, arguments: JSON.stringify(tc.input) }, })), }, }; } catch (error) { safeConsole.error('[DEBUG] AI SDK generateText error:', error); throw error; } }, }; }; //# sourceMappingURL=ai-sdk.js.map