@xynehq/jaf
Version:
Juspay Agent Framework - A purely functional agent framework with immutable state and composable tools
123 lines • 5.85 kB
JavaScript
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