Docs menu
DocsAPI reference

AI chat

chat.listModels, chat.runTurn, streaming tokens, and function calling with your own tools.

Build an in-app model picker from ChatOSS's credential-free model list. Never ask for or handle API keys. Capability: chatApi (declared, never prompts).

List models

const models = await window.chatoss.chat.listModels();
// [{ id, name, source: 'local'|'cloud'|'custom', capabilities,
//    contextLength, available, unavailableReason? }]
const defaultModel = await window.chatoss.chat.getDefaultModel();

Show models in your own <select>; disable rows where available is false. Save the chosen opaque id in your app/project state, then pass it explicitly.

listModels() exposes model ids and display metadata only — never credentials, tokens, or account details.

Run a turn

const result = await window.chatoss.chat.runTurn({
  model: selectedModelId || defaultModel,
  messages: [                       // REQUIRED. Roles: system | user | assistant
    { role: 'system', content: 'You are concise.' },
    { role: 'user', content: 'Hello' }
  ],
  onToken: (t) => { out.textContent += t; },   // streamed reply chunks — use for live UI
  onThinking: (t) => {},            // streamed reasoning, when the model exposes it
  tools: TOOLS,                     // optional function-calling (see below)
  onToolCall: async (call) => '…',  // executes your tools; return a STRING result
  think: true,                      // optional: ask the model to reason first
  signal: abortController.signal    // optional: abort() stops the turn
});
// result = { content, thinking, toolCalls, usage?, aborted }
  • If model is omitted, the app-wide ChatOSS default answers.
  • Multi-turn memory = keep your own messages array and send all of it each turn.
  • Your app's chats see ONLY the tools you pass — never the user's other tools.

Function calling

Describe tools with JSON schema; the engine loops automatically (model calls tool → your onToolCall returns a string → model continues). There is no round limit — the loop runs until the model stops calling tools, so a long orchestration is not truncated part-way. It ends early only if you abort the turn (signal), which sets aborted on the result.

const TOOLS = [{
  type: 'function',
  function: {
    name: 'add_item',
    description: 'Add one item to the list.',
    parameters: {
      type: 'object',
      properties: { text: { 'type': 'string' } },
      required: ['text']
    }
  }
}];
const result = await window.chatoss.chat.runTurn({
  messages: [
    { role: 'system', content: 'Manage the list with tools. Current list:\n' + serialize() },
    { role: 'user', content: userAsk }
  ],
  tools: TOOLS,
  onToolCall: async (call) => {
    const args = call.function.arguments;      // ALREADY PARSED to an object
    if (call.function.name === 'add_item') { addItem(args.text); return 'Added ' + args.text; }
    return 'Error: unknown tool';
  }
});

Include the app's current state in the system message — the model can only act on what it sees.

For driving a full coding-agent loop (multi-round tool use over a project with modes and verification), call the Agent Engine instead — it's the battle-tested engine the built-in Code app uses.