Skip to content

Quick Start ​

One agent, an in-memory store and one manually dispatched run. This is the same code as the example in the @chamberu/core README, which the test suite runs against a scripted model.

ts
import type { LanguageModel } from 'ai';
import { z } from 'zod';
import {
    MemoryStore,
    RunEngine,
    defineAgent,
    defineEffectTool,
    manual,
} from '@chamberu/core';

export async function triageIssue(model: LanguageModel) {
    const labels: string[] = [];

    const triage = defineAgent({
        name: 'triage',
        model,
        instructions: 'Label the issue in the trigger payload as bug, feature or question.',
        triggers: [manual()],
        budget: { maxSteps: 5 },
        tools: () => ({
            // the result is recorded per (run, tool, input): a resumed run reuses it
            addLabel: defineEffectTool({
                description: 'Adds a label to the issue.',
                inputSchema: z.object({ label: z.enum(['bug', 'feature', 'question']) }),
                execute: async ({ label }) => {
                    labels.push(label);
                    return { added: label };
                },
            }),
        }),
    });

    const engine = new RunEngine({
        store: new MemoryStore(),
        agents: [triage],
        resumeSecret: 'change-me',
    });
    await engine.start();

    const { runId } = await engine.dispatch({
        agent: 'triage',
        trigger: 'manual',
        source: 'manual',
        payload: { title: 'App crashes on start' },
    });

    await engine.idle();
    engine.stop();

    return { run: await engine.getRun(runId), labels };
}

Pass any AI SDK LanguageModel, for example anthropic(...) from @ai-sdk/anthropic. The function resolves with the settled run and the labels the tool added.

What happened ​

  1. defineAgent() checked the name and filled in the default budget. The tools factory runs once per execution and returns an AI SDK ToolSet.
  2. new RunEngine() validated the setup: a non-empty resumeSecret, unique agent names, known notifiers.
  3. engine.start() recovered abandoned runs (there were none) and started polling.
  4. engine.dispatch() stored a queued run. The trigger envelope (source, trigger id and payload) became the run's first user message.
  5. The engine claimed the run, set it running and drove an AI SDK ToolLoopAgent. After every step it appended the steps and saved a checkpoint to the store.
  6. The model called addLabel. Because it is an effect tool, its result was recorded under an effect key, so a resumed run would reuse it instead of labelling twice.
  7. The model answered with text, and the run settled completed. Its output is the text of the last answer.
  8. engine.idle() resolved once nothing was running, and engine.stop() stopped the poll.

Where to go next ​

  • Replace MemoryStore with a durable store before you rely on restarts. See Stores.
  • Add a budget, approvals or state.
  • Shut down with drain() instead of stop() in a real process.