naru-agent-js
v0.1.2
Published
Lightweight TypeScript Agent framework with memory, RAG, skills, and guardrails
Readme
naru-agent-js
Lightweight TypeScript Agent framework with memory, RAG, skills, guardrails, and structured decision mode. Built on Vercel AI SDK — supports 100+ LLM providers.
Installation
npm install naru-agent-js
# peer deps (choose your provider)
npm install @ai-sdk/anthropicQuick Start
import { NaruAgent } from "naru-agent-js";
import { anthropic } from "@ai-sdk/anthropic";
const agent = new NaruAgent({
model: anthropic("claude-sonnet-4-5"),
instructions: ["You are a helpful assistant."],
});
const result = await agent.chat("Hello!", "session-1");
console.log(result.content);Core Features
Chat (agent.chat)
Standard conversational mode with full context pipeline — memory, knowledge retrieval, skills, tool calling, guardrails.
const result = await agent.chat("What's the weather?", "session-1", {
userId: "user-123",
});
// result.content, result.usage, result.blockedDecision Mode (agent.decide) — New in 0.1.2
Returns a typed JSON decision instead of generating a natural-language response. Uses the full prefetch pipeline (memory, knowledge, conversation summary) but skips intent/skills/tool-calling steps — ideal for routing, classification, and scoring.
import { NaruAgent, LLMStructuredClassifier } from "naru-agent-js";
import { z } from "zod";
const TriageSchema = z.object({
intent: z.enum(["question", "complaint", "feedback"]),
urgency: z.number().min(1).max(5),
summary: z.string(),
});
const classifier = new LLMStructuredClassifier({
model: anthropic("claude-haiku-4-5"),
schema: TriageSchema,
systemPrompt: "Classify the user message.",
});
const result = await agent.decide("My order hasn't arrived!", classifier, {
userId: "user-123",
includeToolPlan: true, // optional: also plan which tools to call
});
console.log(result.decision);
// { intent: "complaint", urgency: 4, summary: "Missing order" }
console.log(result.trace);
// { classifier, usedMemory, usedKnowledge, toolPlan, ... }DecisionAgentResult<T>
| Field | Type | Description |
|-------|------|-------------|
| decision | T | Typed result from classifier |
| rawText | string | Raw JSON string |
| usage | TokenUsage | Token counts |
| timings | Record<string, number> | Latency breakdown (ms) |
| sessionId | string | Session used |
| traceId | string \| null | Trace ID if tracing enabled |
| trace | object | Classifier name, context flags, tool plan |
ToolPlanner — New in 0.1.2
Determines which tools to call (and with what arguments) without executing them. Useful for preview, audit, or async dispatch.
import { ToolPlanner } from "naru-agent-js";
const planner = new ToolPlanner({ model: anthropic("claude-haiku-4-5") });
const plan = await planner.plan("Book a flight to Tokyo", myTools);
// [{ tool: "search_flights", args: { destination: "Tokyo" } }]LLMStructuredClassifier — New in 0.1.2
Zod-schema-driven classifier using generateObject. Automatically assembles context from summary, memory, and knowledge.
const classifier = new LLMStructuredClassifier({
name: "sentiment",
model: myModel,
schema: z.object({ sentiment: z.enum(["positive", "negative", "neutral"]) }),
systemPrompt: "Classify sentiment.",
});Tools
import { BaseTool } from "naru-agent-js";
import { z } from "zod";
class WeatherTool extends BaseTool {
name = "get_weather";
description = "Get current weather for a city";
parameters = z.object({ city: z.string() });
async execute({ city }: { city: string }) {
return `Weather in ${city}: sunny, 22°C`;
}
}
const agent = new NaruAgent({
model: myModel,
tools: [new WeatherTool()],
});Memory
import { MemoryManager, ChromaMemoryStore } from "naru-agent-js";
const memory = new MemoryManager({
store: new ChromaMemoryStore({ collectionName: "user-memory" }),
model: myModel,
});
const agent = new NaruAgent({ model: myModel, memoryManager: memory });Knowledge (RAG)
import { ChromaKnowledgeStore } from "naru-agent-js";
const knowledge = new ChromaKnowledgeStore({
collectionName: "docs",
embedFn: myEmbedFn,
contextualRetrieval: true, // Anthropic Contextual Retrieval
});
await knowledge.ingest([{ content: "...", metadata: {} }]);
const agent = new NaruAgent({ model: myModel, knowledgeStore: knowledge });Skills
import { BaseSkill, SkillRegistry } from "naru-agent-js";
class SummarySkill extends BaseSkill {
name = "summarize";
triggerWords = ["summarize", "tldr"];
async execute(ctx: SkillContext): Promise<SkillResult> {
return { content: "Here's a summary..." };
}
}
const registry = new SkillRegistry([new SummarySkill()]);
const agent = new NaruAgent({ model: myModel, skillRegistry: registry });Guardrails
import { KeywordGuardrail } from "naru-agent-js";
const agent = new NaruAgent({
model: myModel,
guardrails: [new KeywordGuardrail({ blocklist: ["spam", "abuse"] })],
});Context Compression
Automatically compresses old conversation turns into a rolling summary.
import { ContextCompressor, InMemorySummaryStore } from "naru-agent-js";
const agent = new NaruAgent({
model: myModel,
contextCompressor: new ContextCompressor({
store: new InMemorySummaryStore(),
model: myModel,
triggerTokens: 4000,
}),
});Session Management
import { InMemorySessionStore, RedisSessionStore } from "naru-agent-js";
// Development
const agent = new NaruAgent({ model: myModel, sessionStore: new InMemorySessionStore() });
// Production (multi-instance)
const agent = new NaruAgent({
model: myModel,
sessionStore: new RedisSessionStore({ url: process.env.REDIS_URL }),
});Streaming
for await (const event of agent.stream("Hello!", "session-1")) {
if (event.type === "text_delta") process.stdout.write(event.text);
if (event.type === "done") console.log("\nDone:", event.result.usage);
}Tracing
import { TraceCollector, JsonlTraceExporter } from "naru-agent-js";
const tracer = new TraceCollector({
exporter: new JsonlTraceExporter({ path: "./traces.jsonl" }),
});
const agent = new NaruAgent({ model: myModel, traceCollector: tracer });Vercel / Edge Runtime
All I/O goes through Vercel AI SDK — works in Next.js API routes, Edge functions, and serverless environments.
Changelog
0.1.2
- Decision Mode (
agent.decide<T>) — structured JSON output with full context pipeline - LLMStructuredClassifier — Zod-schema-driven classifier with context assembly
- ToolPlanner — dry-run tool planning without execution
toVercelToolsNoop— no-op tool adapter for planningnormalizeUsage— exported utility to map Vercel AI SDK usage →TokenUsageagent.chatskipparameter to bypass intent/skills/toolCalling per call
0.1.1
- Initial public release
- ReAct agent with tool calling, memory, RAG, skills, guardrails, streaming, tracing
License
MIT
