This commit is contained in:
Zacharias-Brohn
2026-01-14 22:51:46 +01:00
parent e222977f5c
commit c51b3c3fab
14 changed files with 452 additions and 216 deletions
+19 -14
View File
@@ -46,11 +46,12 @@ const tools: Tool[] = [
// --- Tool Implementations ---
const availableTools: Record<string, Function> = {
const availableTools: Record<string, (args: Record<string, unknown>) => string> = {
get_current_time: () => {
return new Date().toLocaleTimeString();
},
calculate: ({ expression }: { expression: string }) => {
calculate: (args) => {
const expression = args.expression as string;
try {
// Safety: simplistic eval for demo purposes.
// In production, use a math parser library like mathjs.
@@ -68,17 +69,19 @@ export async function chat(model: string, messages: ChatMessage[]) {
let response;
try {
response = await ollama.chat({
model: model,
messages: messages,
tools: tools,
model,
messages,
tools,
});
} catch (e: any) {
} catch (e: unknown) {
// Fallback: If model doesn't support tools, retry without them
if (e.message?.includes('does not support tools')) {
const errorMessage = e instanceof Error ? e.message : '';
if (errorMessage.includes('does not support tools')) {
// eslint-disable-next-line no-console
console.warn(`Model ${model} does not support tools. Falling back to standard chat.`);
response = await ollama.chat({
model: model,
messages: messages,
model,
messages,
});
} else {
throw e;
@@ -101,6 +104,7 @@ export async function chat(model: string, messages: ChatMessage[]) {
const functionToCall = availableTools[functionName];
if (functionToCall) {
// eslint-disable-next-line no-console
console.log(`🤖 Tool Call: ${functionName}`, tool.function.arguments);
const functionArgs = tool.function.arguments;
const functionResponse = functionToCall(functionArgs);
@@ -115,9 +119,9 @@ export async function chat(model: string, messages: ChatMessage[]) {
// 3. Send the tool results back to the model to get the final answer
response = await ollama.chat({
model: model,
messages: messages,
tools: tools,
model,
messages,
tools,
});
}
@@ -125,11 +129,12 @@ export async function chat(model: string, messages: ChatMessage[]) {
success: true,
message: response.message,
};
} catch (error: any) {
} catch (error: unknown) {
// eslint-disable-next-line no-console
console.error('Chat error:', error);
return {
success: false,
error: error.message || 'Failed to generate response',
error: error instanceof Error ? error.message : 'Failed to generate response',
};
}
}
+9 -10
View File
@@ -144,21 +144,20 @@ export async function POST(request: NextRequest) {
// Execute each tool and collect results
for (const toolCall of toolCalls) {
controller.enqueue(encoder.encode(`**Using tool: ${toolCall.name}**\n`));
// Use structured markers for frontend parsing
const toolOutput = await executeTool(toolCall.name, toolCall.arguments);
const toolResult = toolOutput.success
? toolOutput.result || ''
: `Error: ${toolOutput.error}`;
const result = await executeTool(toolCall.name, toolCall.arguments);
// Send tool result to stream
if (result.success) {
controller.enqueue(encoder.encode(`\`\`\`\n${result.result}\n\`\`\`\n\n`));
} else {
controller.enqueue(encoder.encode(`Error: ${result.error}\n\n`));
}
// Format: <!--TOOL_START:name:args-->result<!--TOOL_END-->
const toolMarker = `<!--TOOL_START:${toolCall.name}:${JSON.stringify(toolCall.arguments)}-->${toolResult}<!--TOOL_END-->\n\n`;
controller.enqueue(encoder.encode(toolMarker));
// Add tool result to messages for next iteration
workingMessages.push({
role: 'tool',
content: result.success ? result.result || '' : `Error: ${result.error}`,
content: toolResult,
});
}