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

@maozy13/walle

v0.1.7

Published

A TypeScript runtime framework for building tool-using agents.

Readme

WallE

WallE 是一个基于 TypeScript 的 Agent 运行时框架。它通过 NPM 预编译包 @maozy13/neuralink 连接兼容 SSE 的大模型接口,负责维护多轮会话、执行函数工具,并按需召回和更新长期记忆。

当前版本为 0.1.0,依赖 @maozy13/neuralink@^0.1.0。运行 pnpm install 时会直接安装 NeuralLink 的预编译产物,无需克隆或单独构建 NeuralLink 源码。

能力概览

  • 使用统一的 Agent 接口运行多轮 Agentic Loop。
  • 自动识别并并行执行模型返回的函数调用。
  • 使用 Zod 定义工具参数,并在工具执行前完成运行时校验。
  • 启动时发现本地技能,并按任务需要渐进加载完整技能说明。
  • 将会话持久化到本地,支持按 session ID 恢复。
  • 通过可插拔的 MemoryAdapter 召回和更新长期记忆。
  • 内置受限命令工具和交互式 CLI。
  • 复用 NeuralLink 的规范化输入、响应和事件类型。
flowchart LR
    App["应用"] --> Agent
    Agent --> Conversation["Conversation\n会话与持久化"]
    Agent --> Tools["Tools\n工具注册与执行"]
    Agent --> Memory["Memory\n记忆路由"]
    Agent --> NeuralLink["NeuralLink\n模型适配层"]
    NeuralLink --> API["LLM API"]
    Memory --> Adapter["MemoryAdapter"]

环境要求

  • Node.js 18 或更高版本
  • pnpm
  • 支持 SSE 流式响应的模型接口

项目使用 ESM,集成方应使用 ESM,或通过支持 ESM 的构建工具加载。

安装

从 NPM 安装

pnpm add @maozy13/walle

@maozy13/walle 和它依赖的 @maozy13/neuralink 均包含预编译产物,安装完成后即可直接导入使用,无需在应用启动前额外构建。

从源码构建

git clone https://github.com/maozy13/walle.git
cd walle
pnpm install
pnpm build

pnpm install 会从 NPM 安装预编译的 @maozy13/neuralinkpnpm build 仅构建 WallE 自身。

构建完成后,可以将仓库作为本地依赖加入应用:

cd /path/to/your-app
pnpm add /path/to/walle

在 pnpm workspace 中,也可以将 WallE 放入 workspace,并在应用的 package.json 中声明:

{
  "dependencies": {
    "@maozy13/walle": "workspace:*"
  }
}

使用 workspace 方式时,请确保在运行应用前已经构建 WallE。

SDK 集成

WallE 的包入口即 TypeScript SDK。通常只需要创建一个 NeuralLink 连接器,再用它初始化 Agent;工具、会话和记忆均为可选能力。

初始化与流式输出

以下示例连接一个兼容 Responses API 的接口,并实时输出模型回复:

import {
  Agent,
  Connector,
  ResponsesAPIConverter,
  type Response,
} from "@maozy13/walle";

const apiKey = process.env.LLM_API_KEY;
if (apiKey === undefined) {
  throw new Error("LLM_API_KEY is required");
}

const llm = new Connector(
  "https://example.com/v1/responses",
  apiKey,
  new ResponsesAPIConverter(),
);

const agent = new Agent({
  llm,
  instructions: "你是一个简洁、可靠的开发助手。",
  cwd: process.cwd(),
});

/** 提取规范化响应中的可见文本。 */
function responseText(response: Response): string {
  return response.output
    .filter((item) => item.type === "message")
    .map((item) => item.content.type === "output_text"
      ? item.content.text
      : item.content.refusal)
    .join("\n");
}

let rendered = "";
for await (const event of agent.query("your-model", "用一句话介绍 WallE。")) {
  const next = responseText(event.response);
  if (next.startsWith(rendered)) {
    process.stdout.write(next.slice(rendered.length));
  }
  rendered = next;

  if (event.type === "agent.response.failed") {
    throw new Error("Model response failed");
  }
}

Agent.query() 返回 AsyncGenerator<AgentEvent, Response>。每个事件中的 response 都是当前时刻的完整快照,而不是单独的文本增量;流结束时生成器的返回值是最终 Response。如果需要读取这个返回值,请直接循环调用 query.next(),而不是使用 for await...of

Agent 配置

new Agent(options: AgentOptions)

| 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | llm | Pick<Connector, "call"> | 是 | NeuralLink 连接器或实现相同 call() 接口的对象 | | instructions | string | 否 | 每轮模型调用都会注入的系统指令 | | conversation | Conversation | 否 | 自定义会话容器;默认创建空会话 | | tools | Tools | 否 | 自定义工具集;省略时使用包含受限 bash 工具的默认工具集 | | memory | Memory | 否 | 需要注册到 Agent 的记忆系统 | | cwd | string | 否 | 记忆、技能和默认工具的工作目录;默认为 process.cwd() | | home | string | 否 | 用户级技能目录的主目录;默认为当前用户主目录 | | sessionId | string | 否 | 启动时需要从 cwd/.walle/sessions 恢复的会话 ID |

conversationsessionId 通常二选一。若同时传入,Agent 会在提供的 Conversation 对象上加载 sessionId 对应的持久化内容。

发起查询

agent.query(
  model: string,
  input: string | InputItem[],
  optional?: AgentQueryOptions,
): AsyncGenerator<AgentEvent, Response>

| 参数 | 说明 | | --- | --- | | model | 模型服务使用的模型 ID | | input | 文本或 NeuralLink 规范化结构化输入 | | optional.instructions | 仅作用于本次任务的附加系统指令 |

SDK 会自动把当前会话和工具 Schema 发送给模型、执行函数调用、追加工具结果,并继续请求模型,直到当前任务不再产生工具调用或模型返回失败/未完成状态。

响应事件

| 事件 | 含义 | | --- | --- | | agent.response.created | 一轮底层模型响应已创建 | | agent.response.changed | 当前响应的文本、推理或函数调用发生变化 | | agent.response.completed | 一轮底层模型响应完成 | | agent.response.failed | 一轮底层模型响应失败 | | agent.response.incomplete | 一轮底层模型响应提前结束 |

一次 Agent 任务可能包含多轮模型调用,因此可能产生多组 createdchangedcompleted 事件。应以异步生成器结束及其返回的 Response 作为整个任务结束的标志。

如果业务既需要处理事件,又需要最终响应,可以使用以下消费方式:

import type { AgentEvent, AgentQuery, Response } from "@maozy13/walle";

/** 消费完整 Agent 任务,并返回最后一轮规范化响应。 */
async function consumeAgent(
  query: AgentQuery,
  onEvent: (event: AgentEvent) => void,
): Promise<Response> {
  while (true) {
    const next = await query.next();
    if (next.done) return next.value;
    onEvent(next.value);
  }
}

const response = await consumeAgent(
  agent.query("your-model", "分析当前项目"),
  (event) => console.log(event.type),
);

console.log("最终状态:", response.status);

单次查询指令

Agent 会把构造时的 instructions 与单次查询的 instructions 合并:

agent.query("your-model", "审查这段代码", {
  instructions: "只报告会造成运行错误的问题。",
});

使用技能

每个技能是技能目录下的一个文件夹,并包含必需的 SKILL.md

skills/
└── code-review/
    ├── SKILL.md
    └── scripts/

SKILL.md 必须以 YAML front matter 开头。name 只能包含小写字母、数字和连字符,并且必须与技能目录名一致:

---
name: code-review
description: 审查代码并定位可能造成运行错误的缺陷
---

# 执行步骤

按照严重程度检查并报告代码缺陷。

Agent 启动时把技能的 namedescription 构建成 catalog,并注入内置 activate_skill 工具的描述。模型判断技能适用后,会调用该工具;工具只返回 SKILL.md 的指令正文,不包含 Frontmatter。工具结果随后进入当前会话,供下一轮模型调用遵循。没有发现技能时,不会注册该工具。

Agent 按以下优先级增量扫描技能目录:

  1. cwd/.walle/skills
  2. cwd/.agents/skills
  3. ~/.walle/skills
  4. ~/.agents/skills

不同目录中的技能会合并;出现同名技能时,只使用优先级更高位置中的版本。

注册自定义工具

工具是带有名称、描述和 Zod 参数 Schema 的函数。函数名就是暴露给模型的工具名:

如果集成方尚未直接依赖 Zod,请先运行 pnpm add zod。不要依赖 WallE 的传递依赖来解析应用自己的 import。

import { Agent, Tools, type FuncTool } from "@maozy13/walle";
import { z } from "zod";

const weatherParameters = z.object({
  city: z.string().min(1).describe("城市名称"),
}).strict();

interface WeatherResult {
  city: string;
  condition: string;
  temperature: number;
}

/** 查询指定城市的天气。 */
async function get_weather(
  parameters: z.output<typeof weatherParameters>,
): Promise<WeatherResult> {
  // 在这里调用真实的天气服务。
  return {
    city: parameters.city,
    condition: "sunny",
    temperature: 25,
  };
}

const weatherTool: FuncTool<typeof weatherParameters, WeatherResult> = Object.assign(
  get_weather,
  {
    description: "查询指定城市的实时天气",
    parameters: weatherParameters,
  },
);

const tools = new Tools([weatherTool]);
const agent = new Agent({ llm, tools });

也可以稍后注册:

tools.register(weatherTool);

工具参数由 Zod 校验。未知工具、重复名称、非法 JSON 或不符合 Schema 的参数都会作为工具错误返回给模型,由模型决定如何继续。

不传 tools 时,Agent 默认注册内置 bash 工具;显式传入 new Tools(...) 会替换默认工具集。内置工具支持 Bash 命令及 shell 运算符,但拒绝权限、删除和磁盘管理命令;仍应为 Agent 配置权限受限的工作目录和运行账号。

会话与持久化

SDK 模式下,每次查询都会将用户输入、模型输出、函数调用和工具结果写入:

<cwd>/.walle/sessions/<session-id>/CONVERSATION.md
<cwd>/.walle/sessions/<session-id>/ARCHIVES/

新 Agent 会自动生成 session ID,可以通过 agent.conversation.id 获取。恢复已有会话时传入同一个工作目录和 session ID:

const agent = new Agent({
  llm,
  cwd: "/srv/my-agent",
  sessionId: "existing-session-id",
});

如果对应会话不存在或内容无效,构造函数会抛出异常。并发进程不应同时写入同一个 session。

如需自行管理上下文,可以显式创建 Conversation

import { Agent, Conversation } from "@maozy13/walle";

const conversation = new Conversation([], "customer-support-42", process.cwd());
const agent = new Agent({ llm, conversation });

记忆

Memory 负责把模型的召回和更新请求路由到不同的 MemoryAdapter。内置 TermsMemoryAdapter 将术语表保存在 <cwd>/memories/TERMS.md

import { Agent, Memory, TermsMemoryAdapter } from "@maozy13/walle";

const cwd = process.cwd();
const memory = new Memory([
  new TermsMemoryAdapter(cwd),
]);

const agent = new Agent({
  llm,
  cwd,
  memory,
});

配置记忆后,主 Agent 会获得 memory.retrieve 工具。每次任务结束时,WallE 还会启动一次独立的模型循环来判断是否调用 memory.update,因此一次 query() 可能产生额外的模型请求,并会在记忆更新完成后才彻底结束。

自定义适配器需要实现同名的 retrieveupdate 操作:

import type { MemoryAdapter, MemoryOperation } from "@maozy13/walle";

/** 为记忆操作附加模型可读的名称和说明。 */
function memoryOperation(
  name: string,
  description: string,
  callback: (input: string) => unknown | Promise<unknown>,
): MemoryOperation<string> {
  Object.defineProperty(callback, "name", { value: name });
  return Object.assign(callback, { description });
}

const profileMemory: MemoryAdapter = {
  retrieve: memoryOperation(
    "profile",
    "当任务依赖用户偏好时召回用户画像。",
    async (query) => loadProfile(query),
  ),
  update: memoryOperation(
    "profile",
    "当用户明确表达稳定偏好时更新;content 是 JSON 字符串。",
    async (content) => saveProfile(JSON.parse(content)),
  ),
};

loadProfilesaveProfile 由集成方实现。适配器名称必须非空,且两个操作的名称必须一致。

结构化输入

除字符串外,Agent.query() 还接受 NeuralLink 的 InputItem[]

for await (const event of agent.query("your-model", [{
  type: "message",
  role: "user",
  content: [
    { type: "input_text", text: "描述这张图片" },
    { type: "input_image", image_url: "https://example.com/image.png" },
  ],
}])) {
  if (event.type === "agent.response.completed") {
    console.log(responseText(event.response));
  }
}

Responses API 转换器支持规范化的文本、图片和文件输入。NeuralLink 的 Chat Completions 和 Anthropic 转换器当前只支持文本输入;如需在应用中直接导入这些转换器,请将 @maozy13/neuralink 声明为应用的直接依赖,再从该包导入转换器并传给 WallE 的 Agent

CLI

源码构建完成后可以启动交互式 CLI:

node bin/walle.js \
  --base-url https://example.com/v1/responses \
  --model your-model \
  --api-key "$LLM_API_KEY"

CLI 当前使用 Responses API 转换器。输入 /exit/quit 退出。

也可以在运行目录创建 walle.json

{
  "baseUrl": "https://example.com/v1/responses",
  "model": "your-model",
  "apiKey": "replace-with-your-api-key",
  "session": "optional-session-id",
  "log": false
}

CLI 按顺序读取运行目录中的 walle.json、运行目录下的 .walle/walle.json、用户目录下的 ~/.walle/walle.json。配置文件按文件级选择,不会逐项合并。会话保存在所选配置文件同目录下的 sessions/<session-id>;没有配置文件时保存在运行目录下。运行目录中的 WALLE.md 会作为默认系统指令;选中配置文件中的 instruction 会覆盖它,命令行参数的优先级最高。启用日志后,记录写入 logs/<session-id>.log

不要提交包含真实 API Key 的 walle.json,也应避免通过会被 shell 历史记录的命令行参数传入密钥。

查看全部参数:

node bin/walle.js --help

核心 API

| 导出 | 用途 | | --- | --- | | Agent | 组织模型调用、工具执行、会话和记忆生命周期 | | Tools | 注册、列举和执行 Zod 工具 | | Conversation | 管理上下文并持久化 session | | Memory | 注册和路由记忆适配器 | | TermsMemoryAdapter | 基于 Markdown 文件的术语记忆 | | Connector | NeuralLink 模型连接器 | | ResponsesAPIConverter | Responses API 请求与事件转换器 | | resolveCliConfig / runCli | 以代码方式集成 CLI 配置和运行时 |

WallE 同时从包入口重新导出自身及 NeuralLink 的公共类型,包括 AgentOptionsAgentEventFuncToolMemoryAdapterInputItemResponse

数据与安全边界

  • 会话、记忆和可选日志默认以明文写入 cwd,生产环境应自行配置目录权限、备份与清理策略。
  • Connector 当前使用 Authorization: Bearer <apiKey>,其他认证方式需要通过兼容网关适配。
  • 模型接口必须提供 SSE 流;非流式接口不能直接使用。
  • Agent 会用注册工具覆盖单次查询参数中的 tools。动态工具应通过 Tools.register() 管理。
  • 工具结果会被序列化并发送回模型,不要返回不应离开本机的敏感信息。

本地开发

pnpm install
pnpm typecheck
pnpm test
pnpm build

首次执行 pnpm install 时会同时安装可直接使用的 NeuralLink 预编译包,以上开发命令均不再单独编译 NeuralLink。

项目要求单元测试行覆盖率达到 100%,条件覆盖率达到 95% 以上。架构设计以 design/ 目录为唯一来源;实现变更应先核对相应设计文档。

License

当前仓库尚未声明开源许可证。用于分发或商业项目之前,请先与项目维护者确认授权范围。