@ai-zen/agents-sdk

中文文档
1.0.0发布于 2026/11/03MITTypeScriptES Module近 30 天下载 2020

AI-Zen Agents SDK — shared business logic for CLI and Desktop

原始使用文档
文档目录11 节
  1. Source of Truth
  2. Architecture
  3. Module Layering
  4. Core Concepts
  5. Permission Model
  6. Consumption
  7. Development Status
  8. Built-in Tools
  9. Built-in Plugins
  10. Language
  11. Design Principles

@ai-zen/agents-sdk

AI-Zen SDK — shared business logic layer providing a unified Agent runtime for CLI and Desktop. Works out of the box, with preconfigured vendor settings, a default Agent, and a default SubAgent.

Source of Truth

docs/sdk-design-v1.md is the single source of truth for this package's design. All implementations must stay consistent with the document. (Pre-refactor design is kept in docs/sdk-design-v0.md.)

Architecture

CLI ──┐
      ├── @ai-zen/agents-sdk ──┐
Desktop ──┘                    │
                          LLM API

Module Layering

types         ← pure types, zero business dependencies (incl. ToolEnv)
config        ← ConfigManager + constants: config.json read/write + directory setup + factory defaults
crud          ← capability-entity CRUD (Agent definitions; conversations/drafts are persisted by each consumer)
runtime       ← model factory + Agent assembly + task handoff/migration (cancellable via `AbortSignal`; createModel / createAgent / SdkAgent / HandoffService / HandoffGuardPlugin)
scope         ← Scope orchestration container + ScopePlugin contract + PermissionEvaluator / disclosure + plugins/ (5 self-contained capability sources: discovery + tools + plugin)
agent-plugins ← Agent plugins (autoMigrate, autoRefreshTools, contextGuard, unknownToolHint)
shared        ← content blocks (file → content block transport), entity repository, logging, errors

Dependency direction: agent-plugins → runtime → scope; runtime → scope / crud / shared / types, scope → types / shared. Upper layers depend on lower layers.

Core Concepts

EntityDescription
ScopeOrchestration container: global context (config / cwd / agentsDir) + the three-phase capability pipeline (discover → filter → instantiate) + plugin registry. Explicitly assembled via scope.use(...)
ScopePluginCapability plugin (the v1 extension point): self-owns one capability source's discovery state, candidate names, and instantiation (discover / candidates / instantiate / dispose). 5 standard plugins ship out of the box, assembled via allInOne()
ToolEnvTool environment { cwd, config }; injected when the built-in-tools plugin (BuiltinToolsScopePlugin) instantiates tools, serving as the base for relative path resolution and config reads
SdkCallbackToolAbstract base for built-in tools: env constructor injection + subclass call() + resolve() relative path resolution
SdkAgentExtends the Core Agent, carries SDK metadata, supports use() plugin registration
AgentPluginPlugin interface (onInit, onBeforeSend, onAfterSend, onInnerLoopStart, onInnerLoopEnd, onInnerLoopsStart, onInnerLoopsEnd, onToolCall, onUnknownTool, onSubAgentStart, onSubAgentEnd)
EndpointAPI endpoint (baseUrl + apiKey)
ModelModel config, bound to an Endpoint
SubAgentAn Agent with a function field, callable by other Agents as a tool

Permission Model

The four dimensions are independent; allow/deny are mutually exclusive, no match means deny, and permission is disclosure (denied items are completely invisible to the LLM).

Agent.permissions
  ├── tools:      { allow: string[] } | { deny: string[] }
  ├── skills:     { allow: string[] } | { deny: string[] }
  ├── mcps:       { allow: string[] } | { deny: string[] }
  └── subagents:  { allow: string[] } | { deny: string[] }

Consumption

const scope = new Scope({
  config,
  cwd: "/path/to/workspace", // one working directory per Scope; parallel sessions don't interfere
  agentsDir,
}).use(
  ...allInOne({ skillsPaths, toolsPaths, subAgentsPaths, mcpPaths }),
);
await scope.init();

const agent = await createAgent(scope, "my-agent");
const handoffService = new HandoffService({ handoffDir: "/work/.ai-zen/handoffs", skillDirs });
agent.use(new ContextGuardPlugin({ guardTokens, isSuspended: () => handoffService.busy }));
agent.use(new AutoMigratePlugin({ service: handoffService, handoffTokens }));
agent.use(new AutoRefreshToolsPlugin());
agent.use(new UnknownToolHintPlugin({ scope }));
await agent.init();
await agent.send("Hello");

await scope.dispose(); // disconnect MCP, release plugin resources

Development Status

ModuleStatus
types✅ Implemented — core entities, permission model, MCP types complete
config✅ Implemented — ConfigManager + factory defaults + one-shot bootstrap
crud✅ Implemented — capability-entity CRUD for Agents, etc. (conversations/drafts persisted by each consumer)
scope✅ Implemented — Scope + ScopePlugin + 5 standard plugins (builtin / user-tools / skills / mcp / subagents) + allInOne
runtime✅ Implemented — createAgent, MCP connection management, task migration
agent-plugins✅ Implemented — AutoMigratePlugin / AutoRefreshToolsPlugin / ContextGuardPlugin / UnknownToolHintPlugin
shared✅ Implemented — SdkError + injectable Logger

Built-in Tools

All built-in tools are classes (extending SdkCallbackTool), instantiated by the built-in-tools plugin (BuiltinToolsScopePlugin) with a ToolEnv — one set of instances per Scope, with cwd injected and relative paths resolved against Scope.cwd, never depending on the global process.cwd().

ToolDescription
cwdGet the current working directory
readRead a file (optional range for line/column slicing; oversized output warns and suggests batched reads)
inspect_fileInspect a file's structural overview (line count, column distribution, etc.); streamed scan, not limited by the 300KB read threshold
writeWrite a file
execExecute a command (supports timeout; oversized stdout+stderr is dumped to stdout.log / stderr.log)
spawnExecute a command asynchronously, returns immediately without waiting
mkdirCreate a directory
rmDelete a file or directory
globScan and find files using glob patterns (oversized output dumped to result.json)
lsList directory contents (oversized output dumped to result.json)
existCheck whether a file or directory exists
find_textSearch for text or regex in files (oversized output dumped to result.json)
download_fileDownload a file from a URL and save it locally
renameRename or move a file/directory
copyCopy a file or directory
batch_editBatch-edit file text (only unmatched items are echoed back; successful ones are counted)
editEdit text in a file
sleepWait for a specified number of milliseconds

Conditionally injected based on the active model / config:

ToolInjection ConditionDescription
generate_imageOnly when defaultImageModel is configuredGenerate an image from a text description
view_imageOnly for vision models (the agent's modelId resolves to a model with vision: true)View / analyze an image: local images are auto-uploaded via the Files API, network URLs are referenced directly

Tool output protection: AppConfig.maxToolOutput (in characters, default 32768) is the unified ceiling for tool output. Each tool handles overflow itself — exec dumps stdout.log / stderr.log separately (returning head/tail previews per stream), find_text / glob / ls dump result.json (returning a head preview), and read only warns and suggests batched reads via range. Dumps go to <tmpdir>/ai-zen/tool-output/<tool>-<timestamp>-<random>/, one directory per call, with no self-cleanup. See docs/sdk-design-v1.md §12.

Interrupt strategies live in the config: AppConfig.abortedMessageStrategy (keep / drop, factory keep — the model can continue the half-sentence after an interrupt) and AppConfig.abortedToolRoundStrategy (fill / drop, factory fill — whole rounds go in or out, because tool_calls must pair with results). createAgent() reads them from scope.config when no explicit option is passed, keeping a single source of truth.

Built-in Plugins

PluginDescription
AutoMigratePluginAutomatically triggers task migration when usage.prompt_tokens exceeds handoffTokens; delegates the actual migration to the injected HandoffService (history handled per strategy: default omit keeps it auditable, optional prune drops it). resolveMode lets the caller pick the handoff executor or skip the round. Steps aside while service.busy to avoid the handoff→migrate→handoff recursion
AutoRefreshToolsPluginRe-scans the file system before each send() to refresh the tool list
ContextGuardPluginContext safety guard — before each request, throws ContextOverflowError (interrupting the conversation) when the previous round's usage.prompt_tokens exceeds guardTokens (an absolute value: no multiplier, no looser tier), preventing context runaway from reading oversized files. isSuspended() lets the guard itself step aside for handoff/migration turns
UnknownToolHintPluginSmarter unknown-tool hints — when the LLM calls a nonexistent tool, guides it to call_mcp_tool / points out permission issues based on MCP config (opt-in via agent.use)

Language

The SDK is English-only: every model-facing and user-facing string — tool schema descriptions, factory prompts, runtime-injected guidance, tool results, error messages, factory catalog data — is a fixed English literal. There is no locale field, no message catalog, and no runtime language switch. UI language belongs entirely to each consumer (the CLI's i18n/, the Desktop's language setting).

This is a performance boundary, not a convenience choice — SDK behaviour and performance must not vary by the user's language:

  • Thresholds are absolute. Model.tokenThresholds.handoff / guard and AppConfig.maxToolOutput are absolute token / character counts. A localized tool schema is a different token count, so handoff and context-guard would trip at different amounts of real content for the same config.json — same config, different behaviour per language.
  • Schema cost is paid every turn. Description text is re-sent with every request, so a token delta is a standing cost in request size, context usage and spend rather than a one-off.
  • Cache prefixes stop being comparable. Prompt caching matches on the prefix; letting language into the SDK multiplies the prefix shapes of one code path and removes the single variable that benchmarks rely on.
  • Diagnosis needs one shape. Performance data, bug reproductions and tool-call success rates have to be comparable across users; once behaviour drifts with locale, every conclusion needs a "what language are you on?" qualifier first.

Following the user's language is handled by one language-neutral instruction in the factory system prompt — Always reply in the same language the user writes in. — which adapts per message rather than per installation, and needs no locale plumbing in the SDK. Full rationale: docs/sdk-design-v1.md §1.

Design Principles

See the project-root PRINCIPLES.md:

  1. Logical consistency
  2. Design first, documentation as the source of truth
  3. Symmetry and uniformity
  4. No over-engineering
  5. Occam's razor
  6. Refactor as you go; keep clean layering
  7. Tests are the foundation

版本与发布记录

@ai-zen/agents-sdk 共发布 65 个版本,首次发布于 2026/07/18;过去 12 个月发布了 65 个版本。

版本发布日期距今
1.0.0latest2026/11/034 天前
1.0.0-alpha.26alpha2026/11/034 天前
1.0.0-alpha.252026/11/025 天前
1.0.0-alpha.242026/10/299 天前
1.0.0-alpha.232026/10/2910 天前
1.0.0-alpha.222026/10/2810 天前

关于 @ai-zen/agents-sdk 的常见问题

@ai-zen/agents-sdk 是什么?

AI-Zen Agents SDK — shared business logic for CLI and Desktop

如何安装 @ai-zen/agents-sdk?

在项目目录运行 npm install @ai-zen/agents-sdk,或使用 pnpm add / yarn add / bun add。

@ai-zen/agents-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ai-zen/agents-sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@ai-zen/agents-sdk 可以商用吗?

@ai-zen/agents-sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ai-zen/agents-sdk 的下载量有多少?

根据 npm 官方下载统计,@ai-zen/agents-sdk 在 2026/10/05 – 2026/11/03 这 30 天内被下载 2,020 次,日均约 67 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ai-zen/agents-sdk 还在维护吗?

最新版本 1.0.0 发布于 2026/11/03(4 天前);至今共发布 65 个版本,其中过去 12 个月发布了 65 个;首次发布于 2026/07/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。