syaOS syaOS / Docs
GitHub Launch

Chat API

The main AI chat endpoint for syaOS that powers the Chats application. This endpoint handles conversational AI interactions with the "Ryo" persona, supports multiple AI providers, and includes extensive tool calling capabilities for controlling the syaOS system.

Endpoint

MethodPathDescription
POST/api/chatMain AI chat with streaming responses and tool calling

Request

Headers

HeaderRequiredDescription
AuthorizationYesBearer token for authentication (Bearer {token})
X-UsernameYesUsername for the authenticated user
Content-TypeYesMust be application/json

*Required for authenticated users. Anonymous users are allowed with reduced rate limits.

Query Parameters

ParameterTypeRequiredDescription
modelstringNoOverride the AI model (takes precedence over body parameter)

Body

interface ChatRequest {
  // Array of conversation messages
  messages: UIMessage[];
  
  // AI model to use (optional, defaults to "gpt-5.1")
  model?: SupportedModel;
  
  // System state context (optional but recommended)
  systemState?: SystemState;
}

interface UIMessage {
  role: "user" | "assistant" | "system";
  content: string | MessageContent[];
}

interface MessageContent {
  type: "text" | "image";
  text?: string;
  image?: string; // base64 or URL
}

interface SystemState {
  // User identity
  username?: string | null;
  userOS?: string; // e.g., "iOS", "Android", "macOS", "Windows", "Linux"
  locale?: string; // e.g., "en", "zh-TW", "ja", "ko"
  
  // User's local time (from browser)
  userLocalTime?: {
    timeString: string;
    dateString: string;
    timeZone: string;
  };
  
  // Running applications context
  runningApps?: {
    foreground: AppInstance | null;
    background: AppInstance[];
  };
  
  // Internet Explorer state
  internetExplorer: {
    url: string;
    year: string;
    currentPageTitle: string | null;
    aiGeneratedMarkdown?: string | null;
  };
  
  // Video player state
  video: {
    currentVideo: TrackInfo | null;
    isPlaying: boolean;
  };
  
  // iPod state (optional)
  ipod?: {
    currentTrack: TrackInfo | null;
    isPlaying: boolean;
    currentLyrics?: {
      lines: Array<{ startTimeMs: string; words: string }>;
    } | null;
  };
  
  // Karaoke state (optional)
  karaoke?: {
    currentTrack: TrackInfo | null;
    isPlaying: boolean;
  };
  
  // TextEdit state (optional)
  textEdit?: {
    instances: Array<{
      instanceId: string;
      filePath: string | null;
      title: string;
      contentMarkdown?: string | null;
      hasUnsavedChanges: boolean;
    }>;
  };
  
  // Chat room context (for chat room @mentions)
  chatRoomContext?: {
    roomId: string;
    recentMessages: string;
    mentionedMessage: string;
  };
}

interface AppInstance {
  instanceId: string;
  appId: string;
  title?: string;
  appletPath?: string;
  appletId?: string;
}

interface TrackInfo {
  id: string;
  title: string;
  artist?: string;
}

Response

The endpoint returns a Server-Sent Events (SSE) stream using the Vercel AI SDK's UI message stream format.

Stream Format

The response uses Content-Type: text/event-stream and streams data in the following format:

data: {"type":"text-delta","textDelta":"Hello"}
data: {"type":"text-delta","textDelta":" there"}
data: {"type":"tool-call","toolCallId":"...","toolName":"launchApp","args":{...}}
data: {"type":"tool-result","toolCallId":"...","result":{...}}
data: {"type":"finish","finishReason":"stop"}

Error Responses

StatusErrorDescription
400Invalid messages formatMessages array is missing or malformed
400Unsupported modelRequested model is not supported
400Invalid JSONRequest body is not valid JSON
401authentication_failedInvalid or missing authentication token
403UnauthorizedRequest origin not allowed
405Method not allowedOnly POST requests are accepted
429rate_limit_exceededRate limit exceeded for the user
500Internal Server ErrorServer-side error

Rate Limit Error Response

interface RateLimitError {
  error: "rate_limit_exceeded";
  isAuthenticated: boolean;
  count: number;
  limit: number;
  message: string;
}

AI Models

Supported Models

Model IDProviderUnderlying Model
gpt-5.1OpenAIgpt-5.1 (default)
gpt-5OpenAIgpt-5
gpt-5-miniOpenAIgpt-5-mini
gpt-4oOpenAIgpt-4o
gpt-4.1OpenAIgpt-4.1
gpt-4.1-miniOpenAIgpt-4.1-mini
claude-4.5Anthropicclaude-sonnet-4-5
claude-4Anthropicclaude-4-sonnet-20250514
claude-3.7Anthropicclaude-3-7-sonnet-20250219
claude-3.5Anthropicclaude-3-5-sonnet-20241022
gemini-2.5-proGooglegemini-2.5-pro
gemini-2.5-flashGooglegemini-2.5-flash
gemini-3-pro-previewGooglegemini-3-pro-preview

Model Selection

// Priority: Query param > Body param > Default
const model = queryModel || bodyModel || "gpt-5.1";

Rate Limiting

User TypeLimitWindow
Authenticated15 messages5 hours
Anonymous3 messages24 hours

Anonymous users are identified by IP address. The special user "ryo" (with valid token) has unlimited access.

Tool Calling

The Chat API supports extensive tool calling for controlling syaOS applications and system features.

Application Control

launchApp

Launch an application in syaOS.
{
  id: AppId;           // Required: App to launch
  url?: string;        // For internet-explorer: URL to load
  year?: string;       // For internet-explorer: Time-travel year
}

// Available AppIds:
type AppId = 
  | "finder" | "soundboard" | "internet-explorer" | "chats"
  | "textedit" | "paint" | "photo-booth" | "minesweeper"
  | "videos" | "ipod" | "karaoke" | "synth" | "pc"
  | "terminal" | "applet-viewer" | "control-panels" | "admin";

closeApp

Close an application.
{
  id: AppId;  // App to close
}

Media Control

ipodControl

Control iPod playback.
{
  action: "toggle" | "play" | "pause" | "playKnown" | "addAndPlay" | "next" | "previous";
  id?: string;              // YouTube ID or URL (for addAndPlay/playKnown)
  title?: string;           // Track title (for playKnown)
  artist?: string;          // Artist name (for playKnown)
  enableVideo?: boolean;    // Enable video playback
  enableFullscreen?: boolean;
  enableTranslation?: string; // Language code for lyrics translation
}

karaokeControl

Control Karaoke playback (same schema as iPod, without enableVideo).
{
  action: "toggle" | "play" | "pause" | "playKnown" | "addAndPlay" | "next" | "previous";
  id?: string;
  title?: string;
  artist?: string;
  enableFullscreen?: boolean;
  enableTranslation?: string;
}

searchSongs

Search for songs on YouTube.
// Input
{
  query: string;       // Search query (1-200 chars)
  maxResults?: number; // 1-10, default 5
}

// Output
{
  results: Array<{
    videoId: string;
    title: string;
    channelTitle: string;
    publishedAt: string;
  }>;
  message: string;
  hint: string;
}

Virtual File System

list

List items from the virtual file system.
{
  path: "/Applets" | "/Documents" | "/Applications" | "/Music" | "/Applets Store";
  query?: string;  // Search filter (for Applets Store)
  limit?: number;  // Max results 1-50 (for Applets Store)
}

open

Open a file or launch an app.
{
  path: string;  // e.g., "/Applets/Calculator.app", "/Documents/notes.md"
}

read

Read file contents.
{
  path: string;  // Path to file in /Applets, /Documents, or /Applets Store
}

write

Create or modify documents.
{
  path: string;     // e.g., "/Documents/notes.md"
  content: string;  // Document content
  mode?: "overwrite" | "append" | "prepend";
}

edit

Make targeted edits to existing files.
{
  path: string;       // File path
  old_string: string; // Text to replace (must be unique)
  new_string: string; // Replacement text
}

HTML/Applet Generation

generateHtml

Generate an HTML applet for syaOS.
// Input
{
  html: string;    // HTML content (body only)
  title?: string;  // Applet title
  icon?: string;   // Emoji icon
}

// Output (executed server-side)
{
  html: string;
  title: string;
  icon: string;
}

System Settings

settings

Change system preferences.
{
  language?: "en" | "zh-TW" | "ja" | "ko" | "fr" | "de" | "es" | "pt" | "it" | "ru";
  theme?: "system7" | "macosx" | "xp" | "win98";
  masterVolume?: number;     // 0-1
  speechEnabled?: boolean;   // Text-to-speech
  checkForUpdates?: boolean; // Trigger update check
}

Special Tools

aquarium

Render an emoji aquarium in the chat bubble.
{}  // No parameters

Example Usage

Basic Chat Request

const response = await fetch('/api/chat', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${authToken}`,
    'X-Username': 'myusername'
  },
  body: JSON.stringify({
    messages: [
      { role: 'user', content: 'Hello, Ryo!' }
    ],
    model: 'claude-4',
    systemState: {
      username: 'myusername',
      locale: 'en',
      internetExplorer: { url: '', year: 'current', currentPageTitle: null },
      video: { currentVideo: null, isPlaying: false }
    }
  })
});

// Handle SSE stream
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  const chunk = decoder.decode(value);
  // Process SSE events...
}

Using with Vercel AI SDK

import { useChat } from 'ai/react';

function ChatComponent() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: '/api/chat',
    headers: {
      'Authorization': `Bearer ${token}`,
      'X-Username': username
    },
    body: {
      model: 'gpt-5.1',
      systemState: { /* ... */ }
    }
  });

  return (
    <form onSubmit={handleSubmit}>
      <input value={input} onChange={handleInputChange} />
      <button type="submit">Send</button>
    </form>
  );
}

Playing a Song via Tool Calling

The AI will automatically use tools when appropriate:

// User message: "Play Never Gonna Give You Up"

// AI will:
// 1. Call list({ path: "/Music" }) to check library
// 2. If not found, call searchSongs({ query: "Never Gonna Give You Up" })
// 3. Call ipodControl({ action: "addAndPlay", id: "dQw4w9WgXcQ" })

Configuration

Runtime Settings

export const maxDuration = 80;  // Max streaming duration (seconds)
export const runtime = "edge";  // Edge runtime
export const stream = true;     // Enable streaming

Model Configuration

const result = streamText({
  model: selectedModel,
  messages: enrichedMessages,
  tools: { /* ... */ },
  temperature: 0.7,
  maxOutputTokens: 48000,
  stopWhen: stepCountIs(10),  // Max 10 tool-calling steps
  experimental_transform: smoothStream({
    chunking: /[\u4E00-\u9FFF]|\S+\s+/,  // CJK-aware chunking
  })
});

Related Endpoints

EndpointDocumentationDescription
/api/applet-ai-Applet text + image generation
/api/ie-generate-Time-travel page generation
/api/speech-Text-to-speech synthesis
/api/audio-transcribe-Speech-to-text transcription
/api/youtube-search-YouTube music search
/api/song/-Song library CRUD operations

System Prompt Structure

The Chat API uses a layered system prompt approach:

  1. Static System Prompt (cached for performance):
    • Core priority instructions
    • Ryo persona instructions
    • Answer style guidelines
    • Chat instructions
    • Tool usage instructions
    • Code generation instructions
  2. Dynamic System Prompt (per-request):
    • User context (username, OS, locale)
    • Time information (Ryo's time + user's local time)
    • Running applications
    • Media playback state
    • Browser state
    • TextEdit documents
    • Chat room context (if applicable)