Maniac App Pattern
Register agents on a Maniac instance for multi-turn chat with persistent threads and shared defaults.
For applications that serve many turns over time — chat UIs, desktop hosts, channel bots — use the Maniac class instead of calling runAgent directly. Maniac owns shared defaults (model, memory, policy, budget) and routes each turn through a ConversationStore.
Create the app
import { Maniac, OpenAICompatibleModel } from "@maniac-ai/agents";
import { InMemoryMemory } from "@maniac-ai/agents/memory";
const app = new Maniac({
model: new OpenAICompatibleModel({ slug: "gpt-4o-mini" }),
memory: new InMemoryMemory()
});
app.agent({
id: "support",
instructions: "You are a helpful support agent."
});Constructor options include model, memory, policy, budget, observationalMemory, workingMemory, backgroundTasks, and tracerFactory. Per-agent fields on app.agent({ ... }) override app-level defaults for that registration.
Multi-turn chat
chat requires a threadId — it scopes conversation memory:
const result = await app.chat(
"support",
"Where is my order ord_123?",
{ threadId: "thread-1" }
);
const followUp = await app.chat(
"support",
"Can you email me when it ships?",
{ threadId: "thread-1" }
);The second call automatically loads prior turns from the store. Pass resourceId when observational memory uses resource scope (cross-thread recall for the same user).
Streaming
chatStream yields the same StreamEnvelope union as runAgentStream — trace events followed by a final AgentResult:
for await (const envelope of app.chatStream("support", "Hello", { threadId: "thread-1" })) {
if (envelope.type === "event") {
// render trace events (tokens, tool calls, etc.)
} else {
console.log(envelope.result.final);
}
}When to use runAgent instead
runAgent | Maniac.chat |
|---|---|
Caller owns message history (prefixMessages) | ConversationStore loads/saves the thread |
| No memory adapter needed | Requires memory or an explicit conversationStore |
| One-off scripts and unit tests | Long-lived apps with registered agent catalog |
Both paths execute the same runner. See Running agents for budgets, structured output, and pause/resume.