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

@pi-web/agent-kit

v0.1.0

Published

pi-web 自定义 agent 作者的编写面:defineAgent / defineTool / Type。代理类型层,零 pi 依赖。

Readme

@pi-web/agent-kit

pi-web 自定义 agent 时唯一需要的 import。

npm i -D @pi-web/agent-kit
// .pi-web/agents/my-agent/index.ts
import { defineAgent, defineTool, Type } from "@pi-web/agent-kit";

const echo = defineTool({
  name: "echo",
  label: "Echo",
  description: "把传进来的文本原样回显。",
  parameters: Type.Object({
    text: Type.String({ description: "要回显的文本" }),
  }),
  // 第 5 个参数是工具上下文,目前只有 log。不需要它就照旧写 `execute(_id, params)`。
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
    ctx.log("info", "echo 被调用了", { 长度: params.text.length });
    return { content: [{ type: "text", text: params.text }], details: undefined };
  },
});

export default defineAgent({
  systemPrompt: "你是一个最小示例 agent。",
  customTools: [echo],
  tools: ["echo"],       // 在全部平台内置工具之外,再启用 echo
});

工具规则很简单:省略 noTools 时启用全部平台内置工具,再加入 toolsnoTools: "builtin" 先关闭全部内置工具,再启用 tools 中点名的工具; noTools: "all" 关闭所有工具并忽略 toolstools 里重复写内置工具不会报错, 配合 "builtin" 时还可以只重新启用其中几个。

然后 pi-web --agent my-agent "..."。一个 agent 目录 = 一个 agent。

这个包为什么存在

它是一个代理类型层:里面的类型全部由我们自己声明,靠 TypeScript 的结构类型与 pi 的对应 类型兼容,一次强制转换都没有。于是 agent 定义文件里只出现 @pi-web/*,pi SDK 在整个 pi-web 仓库里只有一个引用点(@pi-web/runner,由 tools/check-layers.mjs 机械强制)。

对你的直接好处:写 agent 只装这一个包(几 KB,运行时只有两个恒等函数),不用把整个 pi SDK 拖进你的项目。

代价是结构漂移 —— pi 升级改了形状,这些代理类型不会自动跟着变。配套的机械守卫在 @pi-web/runneragent-conformance.ts:那是唯一同时看得见两边类型的地方,漂移会让 pi-web 自己的 pnpm typecheck 报红,而不是留到运行时。

为什么装它是必须的(不能靠 CLI 里那份副本)

agent 文件由 jiti它自己所在的位置解析 import, 所以 @pi-web/agent-kit 必须能从你的项目里解析到。装在 @pi-web/cli 里的副本它看不见。 顺带,这份 devDependency 也把编辑器里的类型补全给了你。

导出

| | | |---|---| | defineAgent(def) | agent 定义的入口,恒等函数。存在的意义是让对象字面量在声明处就被 AgentDefinition 收窄(不写它就得靠 satisfies,容易漏,写错字段名也不报错) | | defineTool({...}) | 声明单个自定义工具,恒等函数。作用是在数组里保住 parameters 的类型推导 —— 直接把字面量塞进 customTools: [...] 会让 executeparams 退化成 unknown | | Type | typebox 的 schema 构造器,与 pi 精确同版(1.1.38) | | AgentDefinition / ToolDefinition / ToolContext / ToolLogger / ToolLogLevel / ThinkingLevel / TextContent / ImageContent / ToolResult … | 类型 |

工具里怎么打日志

execute 的第 5 个参数是工具上下文,上面有一个 log(级别, 一句话, 附加数据?), 级别是 debug / info / warn / error 四档(跟服务端 --log-level 用的是同一套词, 不用再学一遍)。

同一条日志会出现在两个地方,而这两个地方的过滤规则不一样 —— 这一点最容易踩:

| 在哪儿看 | 长什么样 | 会不会按级别挡掉 | |---|---|---| | 启动 pi-web 的那个终端 | 2026-08-09T… [pi-web:warn] [tool:echo] 你写的那句话 {"toolCallId":"…","你带的字段":…} | 。低于 --log-level / PI_WEB_LOG 那一档的,一行都不打 | | 浏览器页面里的「调试信息」面板 →「运行记录」 | 一条带级别标签的记录,附加数据展开在它下面 | 不会。四档全都送过去 |

所以顺手的做法是:终端留 info 及以上看个大概,debug 那些细节去面板里翻 —— 不用为了看一眼 debug 就改环境变量、重启服务。

两句提醒:

  • 面板上那个「只看」下拉自己也能按级别筛,默认是「全部」。找不到某条 debug 时, 先看看是不是被这个下拉挡住了 —— 服务端一条都没少发,那是浏览器本地的筛选。
  • 面板里的记录只在这个会话活着的时候留着,重启后端就没了。要长期留档, 自己把 pi-web 的终端输出重定向到文件。

日志不会出现在用户读的对话里,也不会混进 pi-web 和 agent 之间的数据通道。 log 不抛异常、不返回东西:一条日志写坏了不该把工具带崩。附加数据要能 JSON 序列化; 序列化不了的(函数、循环引用)不会让整条日志消失 —— 你那句话照发,只有附加数据 会被换成一句说明。

要给用户看一句话(不是排障用的日志),那是另一回事,用 @pi-web/extension-kit 里的 ctx.ui

写 pi 扩展(注册斜杠命令、用 ctx.ui.confirm 弹交互卡片)用配套的 @pi-web/extension-kit

License

MIT