Agents

An agent is a file in agents/ that watches a collection and reacts to each change, like another user would. Its only state is the rows in the database.

agents/tutor.ts
// no watch: a helper, not an agent
import { type Act, isAgent, conversation } from "./room.ts";

export const watch = { collection: "study_events" };

export async function act({ change, server, ai, agent }: Act) {
  const said = change.record;

  // never answer yourself
  if (change.action !== "create" || isAgent(said)) return;
  const room = conversation(server, said.page);

  const written = await ai(
    "You are a friendly tutor. Ask ONE short open question.",
    room.map((e) => `${e.author_name}: ${e.text}`).join("\n"),
    { type: "object", properties: { question: { type: "string" } }, required: ["question"] },
  );
  server.collection("study_events").create({
    page: said.page, author: `agent:${agent}`, author_name: "Tutor", kind: "question",
    // no model: still an answer
    text: written?.question ?? "What do you already know about this?",
  });
}
  • act is called once per change, in order, in the functions sandbox. The file is reloaded each time, so edits apply from the next change.
  • It runs as the system and should mark its own writes. Ignore them, or it will keep replying to itself.
  • ai(system, prompt, schema) calls the model configured in Settings → AI and returns JSON matching the schema, or null if no model is set. Always handle null.
  • Its writes are broadcast like any others: users see them via sync, and other agents watching that collection get them too.

Several agents, one room

A study room might have three agents. The Tutor questions the student it knows least about. The Scribe reads each answer and writes what it learned to study_facts. The Coach watches the facts rather than the conversation, and gives a tip once a student has three. Agents never call each other; they communicate only through rows.

Agents start with the server. If you add a collection while it’s running, restart the server for agents watching it to receive events.