npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@centerseedwu/naru-agent

v0.2.0

Published

Lightweight TypeScript Agent framework with memory, RAG, skills, and guardrails

Readme

naru-agent-js

輕量 TypeScript Agent 框架,支援 orchestration、記憶、RAG、技能、護欄及結構化決策模式。基於 Vercel AI SDK 建構,支援 100+ LLM 供應商。

從單一 agent 到 Swarm 風格的多 agent 路由,同一個框架全部涵蓋。

安裝

npm install naru-agent-js
# peer deps(選擇你的 LLM 供應商)
npm install @ai-sdk/anthropic

架構

┌─────────────────────────────────────────────────────────┐
│ AgentOrchestrator(可選的協作層)                         │
│                                                         │
│ Phase 0: Pending Confirmation(待確認攔截)               │
│ Phase 1: Intent Resolution(確定性 + LLM 分類)          │
│ Phase 2: Direct Execution(高信心度跳過 LLM)            │
│ Phase 3: Delegate(路由到對應的 NaruAgent)               │
└─────────────────────────┬───────────────────────────────┘
                          │
┌─────────────────────────▼───────────────────────────────┐
│ NaruAgent(核心 agent,可獨立使用)                       │
│                                                         │
│  Tools ─ Skills ─ Memory ─ Knowledge(RAG)               │
│  Session ─ Guardrails ─ Compression ─ Tracing           │
└─────────────────────────────────────────────────────────┘

快速開始

單一 Agent

import { NaruAgent } from "naru-agent-js";
import { anthropic } from "@ai-sdk/anthropic";

const agent = new NaruAgent({
  model: anthropic("claude-sonnet-4-5"),
  instructions: ["你是一個實用的助手。"],
});

const result = await agent.chat("你好!", "session-1");
console.log(result.content);

多 Agent 協作

import {
  AgentOrchestrator,
  NaruAgent,
  DeterministicIntentResolver,
  LLMFallbackIntentResolver,
  InMemoryPendingStateManager,
} from "naru-agent-js";

// 各自擁有不同 tools/skills 的專職 agent
const taskAgent = new NaruAgent({ model, tools: [brainDumpTool], instructions: ["你負責任務記錄。"] });
const calAgent  = new NaruAgent({ model, tools: [calendarTool], instructions: ["你負責行事曆查詢。"] });
const general   = new NaruAgent({ model, instructions: ["你是通用助手。"] });

// 基於意圖的路由
const orchestrator = new AgentOrchestrator({
  delegate: general,                              // 預設 fallback
  delegates: new Map([
    ["task_capture", taskAgent],
    ["calendar_query", calAgent],
  ]),
  intentResolver: new LLMFallbackIntentResolver({
    primary: new DeterministicIntentResolver([     // 零 LLM 成本
      { pattern: /記一下|待辦|todo/i, intent: { object: "task_capture", confidence: 1.0 } },
      { pattern: /行事曆|會議|schedule/i, intent: { object: "calendar_query", confidence: 1.0 } },
    ]),
    fallbackAgent: classifierAgent,                // 模糊訊息走 LLM fallback
  }),
  pendingStateManager: new InMemoryPendingStateManager(),
});

const result = await orchestrator.chat("記一下明天要買牛奶", { sessionId: "s1" });
// → taskAgent 處理此訊息
// result.decisionTrace.delegateUsed === "taskAgent"
// result.decisionTrace.phaseReached === "delegate"

最小 Orchestrator(零開銷)

// 僅包裝現有 agent — 行為與 agent.chat() 完全一致
const orchestrator = new AgentOrchestrator({ delegate: myAgent });
const result = await orchestrator.chat("Hello");

核心功能

對話(agent.chat

標準對話模式,完整的上下文管線 — 記憶、知識檢索、技能、工具呼叫、護欄。

const result = await agent.chat("天氣如何?", "session-1", {
  userId: "user-123",
});
// result.content, result.usage, result.blocked

決策模式(agent.decide

回傳型別化的 JSON 決策而非自然語言。使用完整的預取管線但跳過工具執行 — 適合路由、分類和評分。

import { LLMStructuredClassifier } from "naru-agent-js";
import { z } from "zod";

const classifier = new LLMStructuredClassifier({
  model: anthropic("claude-haiku-4-5"),
  schema: z.object({
    intent: z.enum(["question", "complaint", "feedback"]),
    urgency: z.number().min(1).max(5),
  }),
  systemPrompt: "分類使用者訊息。",
});

const result = await agent.decide("我的訂單還沒到!", classifier);
console.log(result.decision);
// { intent: "complaint", urgency: 4 }

工具規劃器(ToolPlanner)

決定要呼叫哪些工具(含參數)但不執行。適合預覽、稽核或非同步派發。

import { ToolPlanner } from "naru-agent-js";

const planner = new ToolPlanner({ model: anthropic("claude-haiku-4-5") });
const plan = await planner.plan("訂一張去東京的機票", myTools);
// [{ tool: "search_flights", args: { destination: "Tokyo" } }]

工具(Tools)

import { tool } from "naru-agent-js";
import { z } from "zod";

const weatherTool = tool({
  name: "get_weather",
  description: "查詢城市目前天氣",
  parameters: z.object({ city: z.string() }),
  execute: async ({ city }) => `${city} 天氣:晴天 22°C`,
});

const agent = new NaruAgent({ model, tools: [weatherTool] });

記憶(Memory)

import { MemoryManager, InMemoryMemoryStore } from "naru-agent-js";

const memory = new MemoryManager({
  store: new InMemoryMemoryStore(),
  model: myModel,
});

const agent = new NaruAgent({ model, memoryManager: memory });

知識庫(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, knowledgeStore: knowledge });

技能(Skills)

import { skill } from "naru-agent-js";

const summarySkill = skill({
  name: "summarize",
  description: "摘要內容",
  triggers: ["摘要", "重點", "tldr"],
  priority: 10,
  run: async (message, context) => ({
    promptInjection: "請簡潔地摘要內容。",
    skillName: "summarize",
  }),
});

const agent = new NaruAgent({ model, skills: [summarySkill] });

護欄(Guardrails)

import { KeywordGuardrail } from "naru-agent-js";

const agent = new NaruAgent({
  model,
  guardrails: [new KeywordGuardrail({ blockedPatterns: ["spam", "abuse"] })],
});

Session 管理

import { InMemorySessionStore, RedisSessionStore } from "naru-agent-js";

// 開發環境
const agent = new NaruAgent({ model, sessionStore: new InMemorySessionStore() });

// 生產環境(多 instance)
const agent = new NaruAgent({
  model,
  sessionStore: new RedisSessionStore({ url: process.env.REDIS_URL }),
});

串流(Streaming)

for await (const event of agent.stream("你好!", "session-1")) {
  if (event.type === "text_delta") process.stdout.write(event.text);
  if (event.type === "done") console.log("\n完成:", event.result.usage);
}

上下文壓縮(Context Compression)

import { ContextCompressor, InMemorySummaryStore } from "naru-agent-js";

const agent = new NaruAgent({
  model,
  contextCompressor: new ContextCompressor({
    store: new InMemorySummaryStore(),
    model: myModel,
    triggerTokens: 4000,
  }),
});

追蹤(Tracing)

import { TraceCollector, JSONLTraceExporter } from "naru-agent-js";

const tracer = new TraceCollector({
  exporter: new JSONLTraceExporter({ path: "./traces.jsonl" }),
});

const agent = new NaruAgent({ model, traceCollector: tracer });

Orchestration API

AgentOrchestrator

透過 4 階段管線路由訊息的協作層。

const orchestrator = new AgentOrchestrator<MyIntentType>({
  // 必要
  delegate: defaultAgent,

  // 多 agent 路由(可選)
  delegates: new Map([["intent_name", specializedAgent]]),

  // 意圖解析(可選)
  intentResolver: myResolver,

  // 快速路徑執行(可選)
  directExecutors: [myExecutor],

  // 狀態管理(可選)
  pendingStateManager: new InMemoryPendingStateManager(),
  sessionStateStore: new InMemorySessionStateStore(),

  // Channel 整合(可選)
  channelAdapter: myChannelAdapter,

  // 生命週期 hooks(可選)
  lifecycleHooks: {
    beforeMessage: async (msg, opts) => { /* 日誌、認證等 */ },
    afterMessage: async (result) => { /* 指標、分析 */ },
    onError: async (error) => { /* 告警 */ },
  },
});

OrchestrationResult

擴展 NaruResult,加上 orchestration 後設資料:

| 欄位 | 型別 | 說明 | |------|------|------| | content | string | 回覆文字(繼承自 NaruResult) | | blocked | boolean | 是否被護欄攔截(繼承自 NaruResult) | | usage | TokenUsage | Token 用量(繼承自 NaruResult) | | toolCalls | string[] | 使用的工具(繼承自 NaruResult) | | orchestrationIntent | OrchestratorIntent<T> \| null | 解析出的意圖 | | decisionTrace | AgentDecisionTrace | 完整決策追蹤含各階段耗時 | | pendingConfirmation | PendingState \| null | 等待使用者確認 | | sessionId | string \| null | Session 識別碼 |

自訂意圖型別

import { GenericIntentObject } from "naru-agent-js";

// 以領域特定意圖擴展
type MyIntent = GenericIntentObject | "task_capture" | "calendar_query" | "reorganize";

// 所有 orchestration 類別完全型別化
const resolver = new DeterministicIntentResolver<MyIntent>([...]);
const orchestrator = new AgentOrchestrator<MyIntent>({ delegate, intentResolver: resolver });
// result.intent?.object 型別為 MyIntent

ChannelAdapter

平台特定訊息處理的抽象介面:

interface ChannelAdapter<TIn, TOut> {
  parseIncoming(input: TIn): ChannelMessage;
  formatOutgoing(result: OrchestrationResult): TOut;
  loadPendingState(sessionId: string): Promise<PendingState | null>;
  savePendingState(sessionId: string, state: PendingState): Promise<void>;
  clearPendingState(sessionId: string): Promise<void>;
}

// 使用方式
const result = await orchestrator.processChannel(rawLineWebhookEvent);

Vercel / Edge Runtime

所有 I/O 透過 Vercel AI SDK — 可在 Next.js API routes、Edge functions 和 serverless 環境中運作。

更新日誌

0.2.0

  • AgentOrchestrator — 4 階段路由:pending → intent → direct execute → delegate
  • DeterministicIntentResolver — 零成本 keyword/regex 意圖匹配
  • LLMFallbackIntentResolver — 確定性 + LLM fallback 組合
  • BaseDirectExecutor — 高信心度操作跳過 LLM
  • ChannelAdapter — 抽象 channel 介面(LINE、Slack、API 等)
  • PendingStateManager — 多步驟確認流程
  • AgentSessionState — 實體追蹤用於指代消解
  • 多 agent 路由 — intent-to-delegate 映射給專職 agent
  • TypeScript 泛型 — 完全型別化的自訂意圖型別

0.1.2

  • 決策模式agent.decide<T>) — 具完整上下文管線的結構化 JSON 輸出
  • LLMStructuredClassifier — 以 Zod schema 驅動的分類器含上下文組裝
  • ToolPlanner — 不執行的工具規劃(dry-run)
  • agent.chatskip 參數可跳過 intent/skills/toolCalling

0.1.1

  • 初始公開發布
  • 具工具呼叫、記憶、RAG、技能、護欄、串流、追蹤的 ReAct agent

授權

MIT