UNPKG

@maximai/maxim-js

Version:

Maxim AI JS SDK. Visit https://getmaxim.ai for more info.

275 lines • 12.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const uuid_1 = require("uuid"); const ai_1 = require("ai"); const openai_1 = require("@ai-sdk/openai"); const v3_1 = require("zod/v3"); const dotenv = __importStar(require("dotenv")); const vercel_1 = require("src/lib/logger/vercel"); const maxim_1 = require("src/lib/maxim"); // Load environment variables dotenv.config(); // Initialize Maxim SDK async function initializeMaxim() { const apiKey = process.env["MAXIM_API_KEY"]; const repoId = process.env["MAXIM_LOG_REPO_ID"]; const baseUrl = process.env["MAXIM_BASE_URL"]; if (!apiKey || !repoId) { throw new Error("MAXIM_API_KEY or MAXIM_LOG_REPO_ID is not defined in the environment variables"); } const maxim = new maxim_1.Maxim({ baseUrl, apiKey, debug: true }); const logger = await maxim.logger({ id: repoId, }); if (!logger) { throw new Error("Logger is not available"); } return { maxim, logger }; } // Define weather tool that will be called const getWeatherInfo = (0, ai_1.tool)({ description: "Get current weather information for a city. Use this tool when the user asks about weather conditions.", inputSchema: v3_1.z.object({ city: v3_1.z.string().describe("Name of the city"), unit: v3_1.z.enum(["celsius", "fahrenheit"]).describe("Temperature unit preferred by the user"), }), execute: async ({ city, unit }) => { console.log(`[WEATHER TOOL] šŸ”§ Executing getWeatherInfo for ${city} in ${unit}`); // Simulate weather data const weatherData = { city, temperature: unit === "celsius" ? 22 : 72, humidity: 65, windSpeed: 12, conditions: "Partly Cloudy", forecast: "Clear skies expected for the next few days", lastUpdated: new Date().toISOString(), unit, }; console.log(`[WEATHER TOOL] āœ… Tool result:`, JSON.stringify(weatherData, null, 2)); return weatherData; }, }); // Main test function async function main() { var _a; const { logger } = await initializeMaxim(); try { // Create a session for testing const sessionId = (0, uuid_1.v4)(); const session = logger.session({ id: sessionId, name: "Weather Prediction Test Session", }); // User message asking for weather prediction const userMessage = { id: (0, uuid_1.v4)(), role: "user", parts: [{ type: "text", text: "What's the weather like in San Francisco today? Please explain the conditions." }], }; const messages = [userMessage]; // Validate UI messages const validatedMessages = await (0, ai_1.validateUIMessages)({ messages }); console.log("\nšŸŒ¤ļø Weather Prediction Test"); console.log("=".repeat(50)); console.log("User question:", (_a = userMessage.parts[0]) === null || _a === void 0 ? void 0 : _a.text); console.log("\nExpected flow:"); console.log("1. Model calls getWeatherInfo tool"); console.log("2. Tool executes and returns weather data"); console.log("3. Model receives tool result"); console.log("4. Model responds with explanation of weather conditions"); console.log("=".repeat(50) + "\n"); // System prompt that encourages tool usage and explanation const systemPrompt = `You are a helpful weather assistant. When users ask about weather: 1. Always use the getWeatherInfo tool to get current weather data 2. After receiving the tool result, provide a clear, friendly explanation of the weather conditions 3. Include details like temperature, conditions, and any relevant information from the tool response 4. Be conversational and helpful`; // Create UI message stream const stream = (0, ai_1.createUIMessageStream)({ execute: async ({ writer: dataStream }) => { console.log("[DEBUG] Starting execute function"); // Convert validated messages to model messages const modelMessages = await (0, ai_1.convertToModelMessages)(validatedMessages, { tools: { getWeatherInfo, }, }); console.log("[DEBUG] Converted to model messages:", modelMessages.length, "messages"); const wrappedModel = (0, vercel_1.wrapMaximAISDKModel)((0, openai_1.openai)("gpt-4o-mini"), logger); // Stream text with Maxim integration const result = (0, ai_1.streamText)({ messages: modelMessages, tools: { getWeatherInfo, }, system: systemPrompt, model: wrappedModel, providerOptions: { maxim: { sessionId: sessionId, traceTags: { environment: process.env["NODE_ENV"] || "test", test_type: "weather_prediction", }, }, openai: {}, }, }); console.log("[DEBUG] streamText called, getting UI message stream"); // toUIMessageStream() automatically handles tool execution and stream consumption const uiStream = result.toUIMessageStream(); console.log("[DEBUG] Got UI message stream, merging..."); dataStream.merge(uiStream); console.log("[DEBUG] Stream merged"); }, generateId: () => (0, uuid_1.v4)(), originalMessages: validatedMessages, }); // Convert stream to SSE format const sseStream = stream.pipeThrough(new ai_1.JsonToSseTransformStream()); // Read the stream to verify it works const reader = sseStream.getReader(); let streamContent = ""; let chunkCount = 0; let toolCallDetected = false; let toolResultDetected = false; let assistantResponseDetected = false; try { while (true) { const { done, value } = await reader.read(); if (done) break; // JsonToSseTransformStream outputs strings directly const chunk = typeof value === "string" ? value : new TextDecoder().decode(value); streamContent += chunk; chunkCount++; // Detect tool call if (chunk.includes("tool-call") || chunk.includes("getWeatherInfo")) { if (!toolCallDetected) { console.log("\nāœ… [TEST] Tool call detected in stream"); toolCallDetected = true; } } // Detect tool result if (chunk.includes("tool-result") || chunk.includes("temperature") || chunk.includes("conditions")) { if (!toolResultDetected && toolCallDetected) { console.log("āœ… [TEST] Tool result detected in stream"); toolResultDetected = true; } } // Detect assistant response (text content after tool result) if (chunk.includes("text-delta") && toolResultDetected && !assistantResponseDetected) { console.log("āœ… [TEST] Assistant response detected"); assistantResponseDetected = true; } // Log first few chunks and tool-related chunks if (chunkCount <= 10) { console.log(`[DEBUG] Chunk ${chunkCount}:`, chunk.substring(0, 150)); } else if (chunk.includes("tool") || chunk.includes("text-delta")) { console.log(`[DEBUG] Important chunk ${chunkCount}:`, chunk.substring(0, 200)); } } } catch (error) { console.error("Error reading stream:", error); throw error; } finally { reader.releaseLock(); } console.log("\n" + "=".repeat(50)); console.log("šŸ“Š Test Results:"); console.log("=".repeat(50)); console.log(`Total chunks received: ${chunkCount}`); console.log(`Total stream length: ${streamContent.length} characters`); console.log(`Tool call detected: ${toolCallDetected ? "āœ… YES" : "āŒ NO"}`); console.log(`Tool result detected: ${toolResultDetected ? "āœ… YES" : "āŒ NO"}`); console.log(`Assistant response detected: ${assistantResponseDetected ? "āœ… YES" : "āŒ NO"}`); // Extract and display assistant response try { const responseMatch = streamContent.match(/"text":"([^"]+)"/g); if (responseMatch && responseMatch.length > 0) { console.log("\nšŸ’¬ Assistant Response Preview:"); console.log("-".repeat(50)); responseMatch.slice(-3).forEach((match, idx) => { const text = JSON.parse(`{${match}}`).text; if (text && text.length > 20) { console.log(text.substring(0, 200) + "..."); } }); } } catch (e) { console.log("\n(Unable to parse response from stream)"); } // Verify test passed const testPassed = toolCallDetected && toolResultDetected && assistantResponseDetected; console.log("\n" + "=".repeat(50)); if (testPassed) { console.log("āœ… TEST PASSED: Tool was called, executed, and assistant responded!"); } else { console.log("āŒ TEST FAILED: Missing required steps"); if (!toolCallDetected) console.log(" - Tool call was not detected"); if (!toolResultDetected) console.log(" - Tool result was not detected"); if (!assistantResponseDetected) console.log(" - Assistant response was not detected"); } console.log("=".repeat(50) + "\n"); // End session session.end(); console.log("āœ… Test completed!"); console.log("Note: Check Maxim dashboard to verify the trace contains tool call, tool result, and assistant response."); } catch (error) { console.error("Error in weather prediction test:", error); throw error; } finally { await logger.cleanup(); } } // Run the test main().catch((error) => { console.error("Fatal error:", error); process.exit(1); }); //# sourceMappingURL=weather_prediction_test.js.map