### Install @photon-ai/rapid Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/reference.md Install the @photon-ai/rapid package using npm, pnpm, or bun. ```bash npm install @photon-ai/rapid pnpm add @photon-ai/rapid bun add @photon-ai/rapid ``` -------------------------------- ### Install Dependencies and Run Project Script Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/README.md Install project dependencies using Bun and run the main project script located at `src/index.ts`. This is part of the repo's development workflow. ```bash bun install # install dependencies bun run src/index.ts ``` -------------------------------- ### Install Rapid AI Dev Toolkit Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/README.md Install the @photon-ai/rapid package using npm, pnpm, or bun. Ensure Node.js 18+ and a TypeScript toolchain are available. ```bash npm install @photon-ai/rapid # or pnpm add @photon-ai/rapid # or bun add @photon-ai/rapid ``` -------------------------------- ### Install Rapid AI Dev Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Install the Rapid AI Dev library using npm. Ensure you have Node.js 18.0.0+ and TypeScript 5.9.3+ installed. The library is ESM-only. ```bash npm install @photon-ai/rapid ``` -------------------------------- ### Run TypeScript Demo with ts-node Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/README.md Execute the `demo.ts` file using the `ts-node` command. This is necessary for running TypeScript examples directly. ```bash ts-node demo.ts ``` -------------------------------- ### Bun Server with WebSockets and Routes Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/CLAUDE.md Example of setting up a server using Bun.serve() that supports HTTP routes and WebSockets. It demonstrates basic request handling and WebSocket communication. ```typescript import index from "./index.html" Bun.serve({ routes: { "/": index, "/api/users/:id": { GET: (req) => { return new Response(JSON.stringify({ id: req.params.id })); }, }, }, // optional websocket support websocket: { open: (ws) => { ws.send("Hello, world!"); }, message: (ws, message) => { ws.send(message); }, close: (ws) => { // handle close } }, development: { hmr: true, console: true, } }) ``` -------------------------------- ### Bun Test Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/CLAUDE.md A basic test case using Bun's built-in testing framework. Ensure 'bun:test' is imported. ```typescript import { test, expect } from "bun:test"; test("hello world", () => { expect(1).toBe(1); }); ``` -------------------------------- ### Multi-Agent Coordination Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/patterns.md This snippet shows how to set up multiple agents that process the same input in parallel using the Rapid AI chat interface. Each agent is defined by an `onInput` handler, allowing for independent logic execution. ```typescript import { renderChatUI } from "@photic-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("Analyzing your input with multiple agents..."); // Agent 1: Sentiment analysis chat.onInput((input) => { const positive = (input.match(/good|great|excellent|happy|love/gi) || []).length; const negative = (input.match(/bad|terrible|awful|sad|hate/gi) || []).length; if (positive > negative) { chat.sendMessage("[Sentiment Agent] Detected positive sentiment"); } else if (negative > positive) { chat.sendMessage("[Sentiment Agent] Detected negative sentiment"); } else { chat.sendMessage("[Sentiment Agent] Neutral sentiment"); } }); // Agent 2: Language detection chat.onInput(async (input) => { // Simulated language detection const hasKanji = /[一-鿿]/.test(input); const language = hasKanji ? "Japanese" : "English"; chat.sendMessage(`[Language Agent] Detected language: ${language}`); }); // Agent 3: Intent classification chat.onInput((input) => { if (input.includes("?")) { chat.sendMessage("[Intent Agent] User is asking a question"); } else if (input.match(/^(hello|hi|hey)/i)) { chat.sendMessage("[Intent Agent] User is greeting"); } else { chat.sendMessage("[Intent Agent] User is making a statement"); } }); await new Promise(() => {}); ``` -------------------------------- ### Running Bun Server with Hot Reloading Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/CLAUDE.md Command to start the Bun server with hot module replacement enabled for development. This command should be run from the project's root directory. ```sh bun --hot ./index.ts ``` -------------------------------- ### Implement Custom Persistence with File System Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Add custom persistence by writing chat logs to a file. This example uses `fs.promises.appendFile` to asynchronously append messages to a log file. ```typescript import * as fs from "fs/promises"; chat.onInput(async (input) => { await fs.appendFile("chat.log", input + "\n"); }); ``` -------------------------------- ### Initialize and Use Chat Controller Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Initialize the chat UI controller and register input handlers or send messages. This is the basic setup for interacting with the chat UI. ```typescript const chat = renderChatUI(); // Register input handlers (can be multiple) chat.onInput(handler1); chat.onInput(handler2); // Send messages programmatically chat.sendMessage("Text to display"); ``` -------------------------------- ### Implement a Command Handler Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md Handles messages starting with '/' as commands. Supports commands like /help, /echo, /count, and /exit. Other messages are echoed back. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("Type /help for commands or a message to echo."); chat.onInput((input) => { if (input.startsWith("/")) { const command = input.slice(1).toLowerCase(); switch (command) { case "help": chat.sendMessage("Commands: /help, /echo, /count, /exit"); break; case "echo": chat.sendMessage("Echo mode: Type a message"); break; case "count": chat.sendMessage("Word count mode: Type a message"); break; case "exit": chat.sendMessage("Goodbye!"); process.exit(0); break; default: chat.sendMessage(`Unknown command: ${command}`); } } else { // Regular message - echo it chat.sendMessage(`You said: ${input}`); } }); await new Promise(() => {}); ``` -------------------------------- ### Import Main Namespace Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Import the main (empty) namespace of the Rapid AI library. This is typically done at the beginning of your project setup. ```typescript // Main (empty) import "@photon-ai/rapid"; ``` -------------------------------- ### Global Error Handling for Initialization Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/errors.md Wrap the entire UI initialization process in a try-catch block to handle any potential errors during setup. This ensures that failures in initialization are caught and logged, allowing for graceful failure or exit. ```typescript try { const chat = renderChatUI(); setupHandlers(chat); } catch (error) { console.error("Failed to initialize chat UI:", error); process.exit(1); } function setupHandlers(chat) { chat.onInput((input) => { // Handler logic }); } ``` -------------------------------- ### Render Chat UI and Handle Input/Messages Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/reference.md Render the chat UI and set up handlers for user input and sending messages. This example demonstrates basic interaction with the chat UI. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("Welcome! Type something:"); chat.onInput((input) => { chat.sendMessage(`You said: ${input}`); }); // Keep the app alive await new Promise(() => {}); ``` -------------------------------- ### Chat Message Usage Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/types.md Demonstrates how the ChatMessage type is used implicitly when interacting with the chat controller and its methods. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); // Messages are created internally with this type // You don't construct ChatMessage directly, but the controller // maintains an array of them chat.sendMessage("Hello!"); // Creates: { role: "assistant", content: "Hello!" } chat.onInput((prompt) => { // prompt is a string, but internally a ChatMessage is created: // { role: "user", content: prompt } }); ``` -------------------------------- ### Concurrent Listener Execution Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Demonstrates that listeners registered with `onInput` execute concurrently, not sequentially, due to the use of `forEach` without awaiting. ```typescript chat.onInput(async (input) => { await delay(1000); console.log("1 done"); }); chat.onInput(async (input) => { console.log("2 done"); }); // Output: "2 done" then "1 done" (concurrent!) ``` -------------------------------- ### Testing Error Conditions (Conceptual) Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/errors.md Illustrates the setup for testing error conditions, specifically noting the difficulty in directly testing scenarios like a null controller due to the library's React/Ink-based nature. Direct testing often requires mocking or integration testing. ```typescript import { test, expect } from "bun:test"; import { renderChatUI } from "@photon-ai/rapid/cli-chat"; test("sendMessage throws if controller is null", async () => { // Difficult to test directly; would require patching createRef // or testing in an integration test with controlled timing }); ``` -------------------------------- ### Clean Application Shutdown Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md Use this snippet to gracefully shut down your application by handling user input for exit commands and SIGINT signals. Ensure the @photon-ai/rapid/cli-chat library is installed. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage('Type "exit" to quit.'); chat.onInput((input) => { if (input.toLowerCase() === "exit") { chat.sendMessage("Goodbye!"); process.exit(0); } else { chat.sendMessage(`You said: ${input}`); } }); // Handle Ctrl+C process.on("SIGINT", () => { console.log("\nInterrupted."); process.exit(0); }); await new Promise(() => {}); ``` -------------------------------- ### Basic Echo Chat Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md A simple chat application that echoes user input back in uppercase. Run this example using `ts-node echo.ts`. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("Welcome! Type anything and I'll echo it back."); chat.onInput(async (prompt) => { chat.sendMessage("Thinking..."); await new Promise(resolve => setTimeout(resolve, 500)); chat.sendMessage(`Echo: ${prompt.toUpperCase()}`); }); // Keep the process alive until Ctrl+C await new Promise(() => {}); ``` ```bash ts-node echo.ts ``` -------------------------------- ### Stateful Conversation Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/patterns.md Maintains application state that evolves through the conversation. Use for games, workflows with state, or when conversation context needs to persist. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; interface GameState { score: number; level: number; health: number; inventory: string[]; } const state: GameState = { score: 0, level: 1, health: 100, inventory: ["sword"], }; const chat = renderChatUI(); chat.sendMessage(`Welcome to the game! Level ${state.level}, Health ${state.health}, Score ${state.score}`); chat.onInput((input) => { if (input === "status") { chat.sendMessage( `Level: ${state.level}, Health: ${state.health}, Score: ${state.score}, Items: ${state.inventory.join(", ")}` ); } else if (input.startsWith("take ")) { const item = input.slice(5); state.inventory.push(item); state.score += 10; chat.sendMessage(`Picked up ${item}! Score: ${state.score}`); } else if (input === "attack") { state.health -= 20; state.score += 50; chat.sendMessage(`Attack! You took damage. Health: ${state.health}, Score: ${state.score}`); } else { chat.sendMessage("Unknown action. Try: status, take , attack"); } }); await new Promise(() => {}); ``` -------------------------------- ### Simulate Streaming Responses Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md Simulates streaming responses by sending multiple messages in sequence. This example shows how to display a response that appears to be streamed by processing chunks over time. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("Type something and I'll stream a response."); chat.onInput(async (input) => { const chunks = [ "Streaming response chunk 1... ", "chunk 2... ", "chunk 3... ", "chunk 4... ", "Done!" ]; let fullResponse = ""; for (const chunk of chunks) { fullResponse += chunk; await new Promise(resolve => setTimeout(resolve, 300)); // Note: We can't truly stream into one message, but we can // show the final result after simulating processing } chat.sendMessage(fullResponse); }); await new Promise(() => {}); ``` -------------------------------- ### Main Entry Point - Namespace Marker Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/source-structure.md This TypeScript file serves as the main entry point for the package, acting as a namespace marker. It uses `export {}` to prevent accidental CommonJS module conversion and guides users to import specific modules via subpath exports. ```typescript // @photon-ai/rapid // Main entry point - import specific modules via subpath exports // Example: import { renderChatUI } from "@photon-ai/rapid/cli-chat" export {}; ``` -------------------------------- ### TypeScript Strict Mode Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Demonstrates the use of TypeScript strict mode with type inference for ChatMessage arrays and InputListener functions. No special comments are required. ```typescript import type { ChatMessage, InputListener } from "@photon-ai/rapid/cli-chat"; // All types are properly inferred const messages: ChatMessage[] = []; const handler: InputListener = (input) => { console.log(input); // input is correctly typed as string }; ``` -------------------------------- ### Register Synchronous and Asynchronous Input Listeners Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/reference.md Example of how to register both synchronous and asynchronous listeners for user input in the chat UI. Ensure asynchronous listeners are handled with care due to sequential execution and potential error propagation. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; import type { InputListener } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); // Synchronous listener const syncListener: InputListener = (input) => { console.log(input); }; // Asynchronous listener const asyncListener: InputListener = async (input) => { const result = await processAsync(input); chat.sendMessage(result); }; chat.onInput(syncListener); chat.onInput(asyncListener); ``` -------------------------------- ### Listener Registration After First Message Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/advanced.md This example demonstrates that input listeners only receive input submitted after their registration. Registering a handler after the UI is rendered and a message has been sent will cause that handler to miss the initial message. ```typescript const chat = renderChatUI(); // User types and sends "hello" setTimeout(() => { chat.onInput((input) => { // Will this handler receive "hello"? // NO - only fires on NEXT user input }); }, 100); ``` -------------------------------- ### Trace Concurrent Handler Execution Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/advanced.md This example demonstrates how to trace the execution of multiple input handlers for a chat instance. It highlights that handlers registered via a loop might run concurrently, not sequentially, due to the lack of awaiting. ```typescript const chat = renderChatUI(); let handlerCount = 0; const handlers = [ async (input: string) => { console.log("[Handler 1] Starting"); await new Promise(resolve => setTimeout(resolve, 100)); console.log("[Handler 1] Done"); }, (input: string) => { console.log("[Handler 2] Running"); }, ]; for (const handler of handlers) { chat.onInput(handler); } // User input will show: // [Handler 1] Starting // [Handler 2] Running (concurrent!) // [Handler 1] Done ``` -------------------------------- ### Initialize and Use Chat UI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/00_START_HERE.md This snippet demonstrates how to quickly set up and interact with the chat UI provided by the library. It covers creating the UI, sending an initial message, and handling user input asynchronously. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; // 1. Create the chat UI const chat = renderChatUI(); // 2. Send an initial message chat.sendMessage("Hello! I'm ready to chat."); // 3. Handle user input chat.onInput(async (userInput) => { // Process the input (call an API, run logic, etc.) const response = await processUserInput(userInput); // Send the response back chat.sendMessage(response); }); // 4. Keep the app running await new Promise(() => {}); ``` -------------------------------- ### Project Structure Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/index.md Illustrates the directory structure of the @photon-ai/rapid project, highlighting the main entry point and the cli-chat module components. ```tree src/ ├── index.ts # Main entry point (empty re-export) └── cli-chat/ ├── index.tsx # Public API and renderChatUI() function ├── chat.tsx # ChatUI component and ChatMessage type ├── message-panel.tsx # Message display component └── input-bar.tsx # Text input component ``` -------------------------------- ### Empty Input Dropped Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Illustrates that empty input submissions are silently dropped and do not trigger registered `onInput` handlers. ```typescript chat.onInput((input) => { console.log(input); // Never logs for empty input }); ``` -------------------------------- ### Initialize and Use Chat UI API Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/reference.md Demonstrates how to initialize the chat UI and attach input listeners and send messages using the imperative API. Ensure the chat UI is rendered before calling these methods. ```typescript const chat = renderChatUI(); chat.onInput(listener1); chat.onInput(listener2); chat.sendMessage("text"); ``` -------------------------------- ### Simple Echo Bot with @photon-ai/rapid Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/patterns.md This snippet demonstrates the most basic usage of @photon-ai/rapid for creating an echo bot. It accepts user input and echoes it back. Use for testing or minimal proof-of-concept. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("I will echo your input. Type something:"); chat.onInput((input) => { chat.sendMessage(`Echo: ${input}`); }); await new Promise(() => {}); ``` -------------------------------- ### Initialize and Use renderChatUI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Initializes the chat UI and registers a handler to echo user messages. Keeps the application running indefinitely. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); // Register a handler chat.onInput((userInput) => { chat.sendMessage(`You said: ${userInput}`); }); // Send a message chat.sendMessage("Welcome!"); // Keep the app alive await new Promise(() => {}); ``` -------------------------------- ### Import Main Namespace Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/reference.md Import the main namespace for the @photon-ai/rapid package. This is a placeholder import. ```typescript import "@photon-ai/rapid"; ``` -------------------------------- ### Initialize CLI Chat UI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Initialize the chat UI. This function call sets up the chat interface for use. ```typescript const chat = renderChatUI(); ``` -------------------------------- ### Implement Rate Limiting for API Calls Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Prevent overwhelming external APIs by implementing rate limiting. This example uses a flag to ensure only one API call is processed at a time. ```typescript let isProcessing = false; chat.onInput(async (input) => { if (isProcessing) return; isProcessing = true; try { await api.call(input); } finally { isProcessing = false; } }); ``` -------------------------------- ### Build Library with Bun Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Execute the build script using Bun to compile TypeScript files. This command generates JavaScript and type definition files in the 'dist/' directory. ```bash bun run build # Outputs: # - dist/index.js (main module) # - dist/index.d.ts (type definitions) # - dist/cli-chat/index.js (CLI chat module) # - dist/cli-chat/index.d.ts (CLI chat types) # - dist/**/*.js and .d.ts for all source files ``` -------------------------------- ### Set Terminal Type with TERM Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Explicitly set the TERM environment variable to control Ink's rendering capabilities and color support. This example sets the terminal type to xterm-256color. ```bash # Explicitly set terminal type TERM=xterm-256color bun run chat.ts ``` -------------------------------- ### Async Handler That Never Completes Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/advanced.md This example shows an async handler that never resolves or rejects. Such a handler can hang the application as the process will wait indefinitely for the promise to settle, preventing other handlers from executing. ```typescript chat.onInput(async (input) => { // Infinite loop or blocked on I/O await new Promise(() => {}); // Never resolves }); ``` -------------------------------- ### Async Initialization of Chat UI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md Initializes the chat UI asynchronously, loads configuration, validates API key, and sets up message handling. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; async function main() { // Load initial data const config = await loadConfiguration(); const apiKey = process.env.API_KEY; // Validate state if (!apiKey) { console.error("API_KEY not set"); process.exit(1); } // Now render the UI const chat = renderChatUI(); chat.sendMessage(`Initialized with config: ${config.name}`); chat.onInput(async (input) => { const response = await callAPI(input, apiKey); chat.sendMessage(response); }); await new Promise(() => {}); } async function loadConfiguration() { return { name: "Default Config" }; } async function callAPI(input: string, apiKey: string): Promise { return `API responded to: ${input}`; } main().catch(console.error); ``` -------------------------------- ### Defensive Initialization with Delay Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/errors.md Use this strategy when the UI might not be ready immediately after rendering. A small delay ensures the UI is initialized before interaction. ```typescript const chat = renderChatUI(); await new Promise(resolve => setImmediate(resolve)); chat.sendMessage("Ready!"); ``` -------------------------------- ### Importing Chat Types Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/types.md Demonstrates how to import specific types like ChatMessage and InputListener from the cli-chat module. Also shows how to infer a function's return type for use as a type annotation. ```typescript // Types are exported from the cli-chat module import type { ChatMessage, InputListener } from "@photon-ai/rapid/cli-chat"; // Or import the function and use its return type import { renderChatUI } from "@photon-ai/rapid/cli-chat"; type ChatController = ReturnType; ``` -------------------------------- ### Basic HTML Structure for Bun Frontend Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/CLAUDE.md A simple HTML file structure that imports a frontend script. Bun automatically handles the transpilation and bundling of linked JavaScript/TypeScript files. ```html

Hello, world!

``` -------------------------------- ### Initialization Data Flow Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/architecture.md Describes the sequence of operations when initializing the chat UI using renderChatUI. ```plaintext renderChatUI() → createRef() → render() → return { onInput, sendMessage } wrapper ``` -------------------------------- ### Importing Rapid AI Dev Modules Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Demonstrates how to import from the main export and the specific CLI chat subpath. The CLI chat module must be imported explicitly using its subpath. ```typescript // Main export (currently empty) import {} from "@photon-ai/rapid"; // CLI chat module (primary usage) import { renderChatUI } from "@photon-ai/rapid/cli-chat"; ``` -------------------------------- ### Rate Limiting and Debouncing Example Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/patterns.md Prevents too many rapid requests to an API by enforcing a minimum interval between requests and checking for ongoing processing. Use for API rate limiting, preventing duplicates, or throttling expensive operations. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; let isProcessing = false; let lastRequestTime = 0; const MIN_INTERVAL_MS = 1000; // At least 1 second between requests const chat = renderChatUI(); chat.sendMessage("Send messages (rate limited to 1 per second)"); chat.onInput(async (input) => { const now = Date.now(); // Rate limit check if (now - lastRequestTime < MIN_INTERVAL_MS) { const waitMs = MIN_INTERVAL_MS - (now - lastRequestTime); chat.sendMessage(`Please wait ${Math.ceil(waitMs / 1000)} seconds`); return; } // Concurrency check if (isProcessing) { chat.sendMessage("Still processing previous request"); return; } isProcessing = true; lastRequestTime = now; try { chat.sendMessage("Processing..."); await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate work chat.sendMessage(`Processed: ${input}`); } catch (error) { chat.sendMessage("Error processing request"); } finally { isProcessing = false; } }); await new Promise(() => {}); ``` -------------------------------- ### Integration Pattern with Agent/LLM Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/cli-chat.md Shows a typical pattern for integrating the CLI chat with an agent or LLM. It initializes the chat, sends a welcome message, and sets up an input handler to process user prompts through an agent, displaying responses or errors. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); chat.sendMessage("Assistant initialized. Send a message to begin."); chat.onInput(async (prompt) => { // Show thinking state chat.sendMessage("Thinking..."); try { // Call your agent or LLM const response = await yourAgent.process(prompt); chat.sendMessage(response); } catch (error) { chat.sendMessage(`Error: ${error.message}`); } }); await new Promise(() => {}); ``` -------------------------------- ### LLM Integration with @photon-ai/rapid and OpenAI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/patterns.md This snippet shows how to integrate @photon-ai/rapid with a language model API, specifically OpenAI. It handles asynchronous API calls, maintains multi-turn conversations, and includes basic error handling. Use for building interactive LLM applications. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const API_KEY = process.env.OPENAI_API_KEY; if (!API_KEY) throw new Error("OPENAI_API_KEY not set"); const chat = renderChatUI(); const conversation: Array<{ role: string; content: string }> = []; chat.sendMessage("Connected to OpenAI. Type your question:"); chat.onInput(async (userInput) => { conversation.push({ role: "user", content: userInput }); chat.sendMessage("Thinking..."); try { const response = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "gpt-4", messages: conversation, temperature: 0.7, }), }); if (!response.ok) { chat.sendMessage(`API Error: ${response.status}`); return; } const data = await response.json(); const assistantMessage = data.choices[0].message.content; conversation.push({ role: "assistant", content: assistantMessage }); chat.sendMessage(assistantMessage); } catch (error) { chat.sendMessage(`Error: ${error instanceof Error ? error.message : "Unknown"}`); } }); await new Promise(() => {}); ``` -------------------------------- ### Render Chat UI and Basic Interaction Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/cli-chat.md Renders the chat UI and demonstrates sending an initial message, registering an input handler, and simulating asynchronous work before responding. Keeps the process alive indefinitely. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; // Render the chat UI and get the controller const chat = renderChatUI(); // Send an initial message chat.sendMessage("Welcome to the chat! Type something to get started."); // Register a handler for user input chat.onInput(async (userPrompt) => { // Process the user input chat.sendMessage("Processing: " + userPrompt); // Simulate async work await new Promise(resolve => setTimeout(resolve, 500)); // Send the response chat.sendMessage("Done! You said: " + userPrompt.toUpperCase()); }); // Keep the process alive. Press Ctrl+C to exit. await new Promise(() => {}); ``` -------------------------------- ### Register Input and Send Message Listeners Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/types.md Demonstrates how to register synchronous and asynchronous listeners for user input and send messages using the chat controller. Ensure the renderChatUI function is imported. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); // Synchronous listener const logListener: InputListener = (input) => { console.log("User said:", input); }; // Asynchronous listener const processListener: InputListener = async (input) => { const result = await processUserInput(input); chat.sendMessage(result); }; chat.onInput(logListener); chat.onInput(processListener); ``` -------------------------------- ### Render CLI Chat UI with Echo Logic Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/README.md Demonstrates how to use the `renderChatUI` function to display a terminal chat interface and echo user input. Requires `ts-node` to run. ```typescript // demo.ts import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const chat = renderChatUI(); chat.sendMessage("Welcome to Rapid! Type anything and I'll echo it back."); chat.onInput(async (prompt) => { chat.sendMessage("Thinking..."); await delay(500); chat.sendMessage(`Echo: ${prompt.toUpperCase()}`); }); // Keep the Ink app alive. Press Ctrl+C to exit. await new Promise(() => {}); ``` -------------------------------- ### Import CLI Chat Module Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Import the necessary functions and types for the CLI chat interface. This is the first step to using the module. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; import type { ChatMessage, InputListener } from "@photon-ai/rapid/cli-chat"; ``` -------------------------------- ### LLM Integration Pattern Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Demonstrates sending user input to an external API (like OpenAI) and relaying the response back to the chat. ```typescript chat.onInput(async (input) => { const response = await fetch("https://api.openai.com/..."); const data = await response.json(); chat.sendMessage(data.choices[0].message.content); }); ``` -------------------------------- ### Using the renderChatUI() Controller API Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Demonstrates how to use the controller object returned by renderChatUI() to manage chat interactions. No configuration object is passed directly to renderChatUI(). ```typescript // No configuration object is passed const chat = renderChatUI(); // All behavior is controlled via returned methods chat.onInput(handler); chat.sendMessage(message); ``` -------------------------------- ### File I/O Operations within Chat Interface Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md This snippet shows how to integrate file system operations (reading and writing) into a chat interface. It handles user commands like '/load ' to read file content and '/save ' to write to a file. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; import * as fs from "fs/promises"; const chat = renderChatUI(); chat.sendMessage('Commands: /load , /save , or just chat'); chat.onInput(async (input) => { try { if (input.startsWith("/load ")) { const filename = input.slice(6); const content = await fs.readFile(filename, "utf-8"); chat.sendMessage(`File contents:\n${content}`); } else if (input.startsWith("/save ")) { const [cmd, filename, ...textParts] = input.split(" "); const text = textParts.join(" "); await fs.writeFile(filename, text); chat.sendMessage(`Saved to ${filename}`); } else { chat.sendMessage(`Echo: ${input}`); } } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; chat.sendMessage(`Error: ${message}`); } }); await new Promise(() => {}); ``` -------------------------------- ### renderChatUI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/cli-chat.md Renders the chat UI and returns a controller for programmatic interaction. The controller allows sending messages and registering input listeners. ```APIDOC ## Function: renderChatUI ### Description Mounts the chat UI as an Ink React application and returns an imperative controller object. The controller allows you to listen for user input and send messages programmatically. ### Signature ```typescript function renderChatUI(): { onInput: (action: InputListener) => void; sendMessage: (message: string) => void; } ``` ### Parameters None ### Return Type An object with the following structure: | Field | Type | Description | |-------|------|-------------| | `onInput` | `(action: InputListener) => void` | Register a callback function to be invoked when the user submits text. The callback receives the trimmed user input string and can be async. Multiple listeners can be registered and will all be invoked sequentially. | | `sendMessage` | `(message: string) => void` | Send a message from the assistant to display in the chat UI. Whitespace is trimmed; empty strings are ignored. | ### Throws - **Error**: "Chat UI is not ready to register input handlers." - thrown by `onInput()` if called before the Ink application fully mounts (rare in practice) - **Error**: "Chat UI is not ready to send messages." - thrown by `sendMessage()` if called before the Ink application fully mounts (rare in practice) ### Example ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; // Render the chat UI and get the controller const chat = renderChatUI(); // Send an initial message chat.sendMessage("Welcome to the chat! Type something to get started."); // Register a handler for user input chat.onInput(async (userPrompt) => { // Process the user input chat.sendMessage("Processing: " + userPrompt); // Simulate async work await new Promise(resolve => setTimeout(resolve, 500)); // Send the response chat.sendMessage("Done! You said: " + userPrompt.toUpperCase()); }); // Keep the process alive. Press Ctrl+C to exit. await new Promise(() => {}); ``` ### Input Listener Type **Type**: `InputListener` **Definition**: `type InputListener = (input: string) => void` **Source**: `src/cli-chat/index.tsx:5` A callback function that receives the user's submitted input (trimmed string). The function can be synchronous or asynchronous. Async listeners are awaited sequentially before the next listener is invoked. ``` -------------------------------- ### Handling Sequential Async Input in CLI Chat Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/cli-chat.md Demonstrates how to use sequential asynchronous input handlers. Each handler is awaited before the next is invoked, preventing race conditions. ```typescript const chat = renderChatUI(); chat.onInput(async (input) => { // This will complete before the next listener is called await someAsyncOperation(); }); chat.onInput(async (input) => { // This waits for the previous listener to complete await anotherAsyncOperation(); }); ``` -------------------------------- ### Implement a State Machine Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/advanced.md Use this pattern to manage complex workflows with distinct states and transitions. Ensure all necessary states and transitions are clearly defined. ```typescript type State = "idle" | "waiting-name" | "waiting-age" | "complete"; interface AppState { current: State; name: string; age: number; } const state: AppState = { current: "idle", name: "", age: 0, }; const chat = renderChatUI(); function transition(newState: State, message: string) { state.current = newState; chat.sendMessage(message); } chat.sendMessage("What is your name?"); transition("waiting-name", ""); chat.onInput((input) => { switch (state.current) { case "idle": transition("waiting-name", "What is your name?"); break; case "waiting-name": state.name = input; transition("waiting-age", "How old are you?"); break; case "waiting-age": state.age = parseInt(input, 10); transition("complete", `Hello ${state.name}, age ${state.age}`); break; case "complete": chat.sendMessage("Done!"); break; } }); await new Promise(() => {}); ``` -------------------------------- ### package.json Configuration for Rapid AI Dev Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Defines the package name, version, module type, and entry points for the library. It specifies ESM-only support and details both the root and subpath exports. ```json { "name": "@photon-ai/rapid", "version": "1.0.1", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" }, "./cli-chat": { "types": "./dist/cli-chat/index.d.ts", "import": "./dist/cli-chat/index.js" } } } ``` -------------------------------- ### Multiple Input Listeners Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/cli-chat.md Demonstrates registering multiple input listeners for the chat UI. Each listener is invoked sequentially for every user submission, allowing for parallel logging and processing of input. ```typescript const chat = renderChatUI(); // First listener logs all input chat.onInput((input) => { console.log("[LOG]", input); }); // Second listener processes with agent chat.onInput(async (input) => { const response = await agent.chat(input); chat.sendMessage(response); }); // Both will be called for each user input await new Promise(() => {}); ``` -------------------------------- ### renderChatUI Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/source-structure.md Renders the command-line chat user interface and returns an object to control it. This function is the primary entry point for using the CLI chat module. ```APIDOC ## renderChatUI ### Description Renders the command-line chat user interface and returns an object to control it. This function is the primary entry point for using the CLI chat module. ### Method ``` export function renderChatUI(): { onInput: (action: InputListener) => void; sendMessage: (message: string) => void; } ``` ### Parameters This function does not accept any parameters. ### Returns An object with the following methods: - **onInput** (`(action: InputListener) => void`): Registers a callback function to be executed when the user provides input. - **sendMessage** (`(message: string) => void`): Sends a message to the chat UI, which will be displayed as an assistant's response. ### Request Example ```javascript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chatController = renderChatUI(); chatController.onInput((input) => { console.log("User input received:", input); }); // To send a message from the assistant perspective: // chatController.sendMessage("Hello from the assistant!"); ``` ### Response This function does not return a direct response body. It returns a controller object for interacting with the chat UI. #### Success Response (Controller Object) The returned object has the following methods: - **onInput** (`(action: InputListener) => void`): A function to register input listeners. It takes a callback function that receives the user's input string. - **sendMessage** (`(message: string) => void`): A function to send messages to the chat UI. It takes a string message to be displayed as an assistant's response. #### Response Example ```json { "onInput": "function", "sendMessage": "function" } ``` ``` -------------------------------- ### Type-Safe Input Handlers Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/quick-start.md Demonstrates using TypeScript types for full type safety with input listeners. Two handler functions are shown: one that converts input to uppercase and another that logs the input. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; import type { InputListener, ChatMessage } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); // Type-safe handler function const messageHandler: InputListener = (input) => { // TypeScript knows input is a string const upperCase: string = input.toUpperCase(); chat.sendMessage(upperCase); }; chat.onInput(messageHandler); // Type-safe handler in arrow form const logHandler: InputListener = (input) => { console.log(`User said: ${input}`); // input is string }; chat.onInput(logHandler); await new Promise(() => {}); ``` -------------------------------- ### Handling Secrets in Application Code Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Demonstrates how to integrate the library while managing secrets like API keys within your application. Secrets should be sourced from environment variables or secure storage. ```typescript import { renderChatUI } from "@photon-ai/rapid/cli-chat"; const chat = renderChatUI(); // Secrets should come from environment or secure storage const apiKey = process.env.OPENAI_API_KEY; chat.onInput(async (input) => { // Use the secret in your handler const response = await fetch("https://api.openai.com/v1/chat/completions", { headers: { "Authorization": `Bearer ${apiKey}` } }); const text = await response.text(); chat.sendMessage(text); }); ``` -------------------------------- ### CLI Chat Module - Sequential Listener Invocation Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/source-structure.md This snippet shows how user input is processed by invoking all registered listeners sequentially in the order they were added. Each listener receives the user's message as an argument. ```typescript listeners.current.forEach((listener) => { listener(message); }); ``` -------------------------------- ### CLI Chat Module - Render Chat UI Function Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/source-structure.md The `renderChatUI` function initializes and renders the chat controller using Ink's `render` function. It returns a wrapper object that provides methods to interact with the chat UI, including registering input handlers and sending messages. ```typescript export function renderChatUI(): { onInput: (action: InputListener) => void; sendMessage: (message: string) => void; } { const controllerRef = createRef(); render(); return { onInput(action) { if (!controllerRef.current) { throw new Error("Chat UI is not ready to register input handlers."); } controllerRef.current.onInput(action); }, sendMessage(message) { if (!controllerRef.current) { throw new Error("Chat UI is not ready to send messages."); } controllerRef.current.sendMessage(message); }, }; } ``` -------------------------------- ### npm Package Files Configuration Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md The 'files' property in the package.json specifies which files are included when the package is published to npm. Only compiled output, documentation, and license are included. ```json { "files": [ "dist", "README.md", "LICENSE" ] } ``` -------------------------------- ### Configure Input Handler with Conditional Logic Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/configuration.md Set up an input handler that executes different logic based on the input content. This allows for distinguishing between commands and regular messages. ```typescript chat.onInput((input) => { if (input.startsWith("/")) { // Command mode handleCommand(input.slice(1)); } else { // Message mode forwardToAgent(input); } }); ``` -------------------------------- ### Multiple Handlers Pattern Source: https://github.com/photon-hq/rapid-ai-dev/blob/main/_autodocs/README.md Illustrates registering multiple input handlers that will all be executed concurrently for each user input. ```typescript chat.onInput((input) => { /* handler 1 */ }); chat.onInput((input) => { /* handler 2 */ }); chat.onInput((input) => { /* handler 3 */ }); // All three run for each input (concurrently!) ```