UNPKG

@maximai/maxim-js

Version:

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

239 lines • 8.82 kB
"use strict"; /** * Interactive chat with OpenAI Realtime API + Maxim logging + Tool Calling * * Run with: npx ts-node src/lib/tests/openai/realtime_chat.ts */ 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 dotenv_1 = require("dotenv"); (0, dotenv_1.config)(); const readline = __importStar(require("readline")); const ws_1 = require("openai/realtime/ws"); const index_1 = require("../../../../index"); const realtime_1 = require("../../logger/openai/realtime"); // Define tools const tools = [ { type: "function", name: "get_weather", description: "Get the current weather for a location", parameters: { type: "object", properties: { location: { type: "string", description: 'City name, e.g. "San Francisco"' }, unit: { type: "string", enum: ["celsius", "fahrenheit"], description: "Temperature unit" }, }, required: ["location"], }, }, { type: "function", name: "calculate", description: "Perform a mathematical calculation", parameters: { type: "object", properties: { expression: { type: "string", description: 'Math expression to evaluate, e.g. "2 + 2 * 3"' }, }, required: ["expression"], }, }, { type: "function", name: "get_time", description: "Get the current date and time", parameters: { type: "object", properties: { timezone: { type: "string", description: 'Timezone, e.g. "America/New_York"' }, }, }, }, ]; // Tool implementations function executeTool(name, args) { console.log(`\nšŸ”§ Calling tool: ${name}(${JSON.stringify(args)})`); switch (name) { case "get_weather": { const location = args["location"] || "Unknown"; const unit = args["unit"] || "fahrenheit"; const temp = unit === "celsius" ? Math.floor(Math.random() * 30 + 5) : Math.floor(Math.random() * 50 + 40); const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"][Math.floor(Math.random() * 4)]; return JSON.stringify({ location, temperature: temp, unit, conditions }); } case "calculate": { try { // Simple safe eval for basic math const expr = String(args["expression"]).replace(/[^0-9+\-*/().% ]/g, ""); const result = Function(`"use strict"; return (${expr})`)(); return JSON.stringify({ expression: args["expression"], result }); } catch { return JSON.stringify({ error: "Invalid expression" }); } } case "get_time": { const tz = args["timezone"] || "UTC"; try { const now = new Date().toLocaleString("en-US", { timeZone: tz }); return JSON.stringify({ timezone: tz, datetime: now }); } catch { return JSON.stringify({ timezone: "UTC", datetime: new Date().toISOString() }); } } default: return JSON.stringify({ error: `Unknown tool: ${name}` }); } } const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); async function main() { const openAIKey = process.env["OPENAI_API_KEY"]; const maximApiKey = process.env["MAXIM_API_KEY"]; const repoId = process.env["MAXIM_LOG_REPO_ID"]; if (!openAIKey || !maximApiKey || !repoId) { console.error("Set OPENAI_API_KEY, MAXIM_API_KEY, and MAXIM_LOG_REPO_ID"); process.exit(1); } const maxim = new index_1.Maxim({ apiKey: maximApiKey, baseUrl: process.env["MAXIM_BASE_URL"] }); const logger = await maxim.logger({ id: repoId }); if (!logger) { console.error("Failed to create logger"); process.exit(1); } const rt = new ws_1.OpenAIRealtimeWS({ model: "gpt-4o-realtime-preview-2024-12-17" }); const wrapper = (0, realtime_1.wrapOpenAIRealtime)(rt, logger, { "maxim-session-name": "Realtime Chat Example", "maxim-session-tags": { test: "val", test2: "val2", }, }); rt.socket.on("open", () => { rt.send({ type: "session.update", session: { type: "realtime", output_modalities: ["text"], instructions: "You are a helpful assistant with access to tools. Use them when appropriate. Be concise.", tools, }, }); }); rt.on("session.updated", () => { console.log('\nšŸ’¬ Chat started. Type your message and press Enter. Type "exit" to quit.'); console.log("šŸ“¦ Available tools: get_weather, calculate, get_time\n"); promptUser(); }); rt.on("response.output_text.delta", (event) => { process.stdout.write(event.delta); }); // Handle function calls rt.on("response.function_call_arguments.done", (event) => { const callId = event.call_id; const name = event.name; let args = {}; try { args = JSON.parse(event.arguments || "{}"); } catch { // ignore parse errors } // Execute the tool const result = executeTool(name, args); console.log(` Result: ${result}`); // Send result back rt.send({ type: "conversation.item.create", item: { type: "function_call_output", call_id: callId, output: result, }, }); // Request continuation rt.send({ type: "response.create" }); }); rt.on("response.done", (event) => { var _a; // Check if there were function calls (don't prompt if waiting for tool response) const output = ((_a = event.response) === null || _a === void 0 ? void 0 : _a.output) || []; const hasFunctionCalls = output.some((item) => item.type === "function_call"); if (!hasFunctionCalls) { console.log("\n"); promptUser(); } }); rt.on("error", (err) => { console.error("\nāŒ Error:", err.message || err); promptUser(); }); function promptUser() { rl.question("You: ", (input) => { const text = input.trim(); if (text.toLowerCase() === "exit") { cleanup(); return; } if (!text) { promptUser(); return; } process.stdout.write("Assistant: "); rt.send({ type: "conversation.item.create", item: { type: "message", role: "user", content: [{ type: "input_text", text }] }, }); rt.send({ type: "response.create" }); }); } async function cleanup() { console.log("\nšŸ‘‹ Goodbye!"); rl.close(); rt.close(); wrapper.cleanup(); await (logger === null || logger === void 0 ? void 0 : logger.flush()); await (logger === null || logger === void 0 ? void 0 : logger.cleanup()); await maxim.cleanup(); process.exit(0); } rt.socket.on("close", cleanup); } main().catch(console.error); //# sourceMappingURL=realtime_chat.js.map