- Migrate to LangChain for model abstraction (@langchain/anthropic, @langchain/ollama) - Add custom ChatCloudflare class for Cloudflare Workers AI - Simplify API routes using unified LangChain interface - Add session preferences API for storing user settings - Add connection label preference (ask user once, remember for session) - Add shape modification support (change entity shapes via AI) - Add template setter to DiagramObject for shape changes - Improve entity inference with fuzzy matching - Map colors to 16 toolbox palette colors - Limit conversation history to last 6 messages - Fix model switching to accept display names Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
98 lines
3.6 KiB
JavaScript
98 lines
3.6 KiB
JavaScript
import { Router } from "express";
|
|
import { getSession, addMessage } from "../services/sessionStore.js";
|
|
import {
|
|
getOllamaModel,
|
|
buildLangChainMessages,
|
|
aiMessageToClaudeResponse
|
|
} from "../services/langchainModels.js";
|
|
|
|
const router = Router();
|
|
|
|
router.post("/*path", async (req, res) => {
|
|
const requestStart = Date.now();
|
|
console.log(`[Ollama API] ========== REQUEST START ==========`);
|
|
|
|
const { sessionId, model: modelId, max_tokens, system: systemPrompt, messages } = req.body;
|
|
|
|
console.log(`[Ollama API] Session ID: ${sessionId || 'none'}`);
|
|
console.log(`[Ollama API] Model: ${modelId}`);
|
|
console.log(`[Ollama API] Messages count: ${messages?.length || 0}`);
|
|
|
|
try {
|
|
// Get LangChain model with tools bound
|
|
const model = getOllamaModel(modelId);
|
|
|
|
// Build messages with entity context and history
|
|
const langChainMessages = buildLangChainMessages(
|
|
sessionId,
|
|
messages,
|
|
systemPrompt
|
|
);
|
|
|
|
console.log(`[Ollama API] Sending request via LangChain...`);
|
|
const fetchStart = Date.now();
|
|
|
|
// Invoke model
|
|
const response = await model.invoke(langChainMessages);
|
|
|
|
const fetchDuration = Date.now() - fetchStart;
|
|
console.log(`[Ollama API] Response received in ${fetchDuration}ms`);
|
|
|
|
// Convert to Claude API format for client compatibility
|
|
const claudeResponse = aiMessageToClaudeResponse(response, modelId);
|
|
console.log(`[Ollama API] Response converted. Stop reason: ${claudeResponse.stop_reason}, content blocks: ${claudeResponse.content.length}`);
|
|
|
|
// Store messages to session if applicable
|
|
if (sessionId && claudeResponse.content) {
|
|
const session = getSession(sessionId);
|
|
if (session) {
|
|
const userMessage = messages?.[messages.length - 1];
|
|
if (userMessage && userMessage.role === 'user' && typeof userMessage.content === 'string') {
|
|
addMessage(sessionId, {
|
|
role: 'user',
|
|
content: userMessage.content
|
|
});
|
|
console.log(`[Ollama API] Stored user message to session`);
|
|
}
|
|
|
|
const assistantContent = claudeResponse.content
|
|
.filter(c => c.type === 'text')
|
|
.map(c => c.text)
|
|
.join('\n');
|
|
|
|
if (assistantContent) {
|
|
addMessage(sessionId, {
|
|
role: 'assistant',
|
|
content: assistantContent
|
|
});
|
|
console.log(`[Ollama API] Stored assistant response to session (${assistantContent.length} chars)`);
|
|
}
|
|
}
|
|
}
|
|
|
|
const totalDuration = Date.now() - requestStart;
|
|
console.log(`[Ollama API] ========== REQUEST COMPLETE (${totalDuration}ms) ==========`);
|
|
res.json(claudeResponse);
|
|
|
|
} catch (error) {
|
|
const totalDuration = Date.now() - requestStart;
|
|
console.error(`[Ollama API] ========== REQUEST FAILED (${totalDuration}ms) ==========`);
|
|
console.error(`[Ollama API] Error:`, error);
|
|
|
|
// Check if it's a connection error
|
|
if (error.cause?.code === 'ECONNREFUSED' || error.message?.includes('ECONNREFUSED')) {
|
|
return res.status(503).json({
|
|
error: "Ollama is not running",
|
|
details: `Could not connect to Ollama. Make sure Ollama is installed and running.`
|
|
});
|
|
}
|
|
|
|
res.status(500).json({
|
|
error: "Failed to call Ollama",
|
|
details: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
export default router;
|