Skip to main content

yier-agents

Python Agent 系统,参考 OpenCode 架构设计,支持工具调用、子 Agent 和基于 finish_reason 的循环控制。

版本更新与不兼容变更见 CHANGELOG · v0.4.0。changelog 随源码包发布,并包含在 wheel 的 yier_agents-0.4.0.data/data/share/yier_agents/CHANGELOG.md 中(安装后位于 Python 环境的 share/yier_agents/CHANGELOG.md)。

特性

  • ✅ finish_reason 驱动循环 - 自动处理工具调用和 token 限制
  • ✅ Pydantic 参数验证 - 类型安全的工具定义
  • ✅ ToolMiddleware - 统一的工具管理和错误处理
  • ✅ SubAgent 支持 - Agent 可以作为工具被其他 Agent 调用
  • ✅ 并发工具执行 - 使用 asyncio.gather 并行执行
  • ✅ OpenAI-compatible API - 支持任何兼容 OpenAI 格式的 LLM
  • ✅ 内置 Todo 工具 - AI 自动管理任务列表和进度跟踪
  • ✅ Verbose 调试模式 - 美观的彩色输出,实时查看执行过程
  • ✅ MCP 支持(可选依赖)- 通过 MCPClient 连接任意 MCP server,自动转换为 Tool 实例,支持 stdio 和 SSE 两种传输
  • ✅ 会话记忆 - 自动保存和加载会话上下文,支持多轮对话
  • ✅ Skill 支持 - 通过 Skill 打包 system prompt 和 tools,复用 Agent 能力
  • ✅ 上下文压缩 - 长对话可自动摘要旧消息,保留最近上下文
  • ✅ 可持久化记忆 - 通过 JSONSessionStore 将 session memory 持久化到磁盘
  • ✅ 思考过程支持 - 支持 reasoning_content 字段,兼容 o1、Claude thinking 等模型
  • ✅ 交互式 CLI 助手 - 内置 yier-cli,支持会话记忆、skills、MCP 和工作区工具
  • ✅ PTY 终端与任务排队 - 长任务可后台执行,完成后自动提醒并触发后续 follow-up

宿主应用集成

已针对 Bubu 的集成反馈重构公共 API:MCP 内存配置与租约、公开协议模型和工具适配器、JSON Schema 本地校验、统一 Agent 执行循环、真实 SSE token 流、取消/deadline、中间件与动态工具,以及异步会话存储适配和原子文件写入。

本轮进一步统一了事件信封与结果载荷、宿主日志、显式模型配置和 token 预算压缩,迁移见 宿主契约加固。

完整示例、行为约定与兼容性变化见 宿主集成与迁移说明。其中 MCPManager() 默认空配置,文件模式需显式传 config_dir;同名工具默认报错;LLM 库层不再读取 .env 或弹出配置询问。

安装

# 使用 uv
uv pip install -e .

# 或使用 pip
pip install -e .

可选依赖:MCP

MCP 支持是可选的,需要额外安装:

pip install "yier_agents[mcp]"

之所以拆成 extra,是因为 mcp 包会带进 starlette、uvicorn、pyjwt、jsonschema 等一大串传递依赖,而它们经常和宿主应用已锁定的版本冲突。不装也不影响其它功能——import yier_agents 照常可用,只是真正去连接 MCP server 时会提示你安装。

打包与发版

推荐通过 Makefile 管理版本和构建产物,这样每次打包前都会先清掉旧的 dist/、build/ 和 *.egg-info,避免安装到旧 wheel,或者看到过期的 METADATA。

# 查看当前版本
make version

# 只在本地完成 patch 发版准备
make tag-release-patch

# 本地准备后顺序推送分支和 tag
make publish-release-patch

常用命令:

  • make build - 清理旧产物后重新生成 wheel 和 sdist,并执行 twine check
  • make metadata - 查看最新 wheel 中的 METADATA
  • make pkg-info - 查看最新 sdist 中的 PKG-INFO
  • make install-wheel - 使用 uv pip install --reinstall 安装最新 wheel,避免同版本安装时残留旧元数据
  • make tag-release-patch - 顺序执行 bump、build、test、commit 和 tag,但不推送
  • make publish-release-patch - 在 tag-release-patch 基础上继续 push 当前分支和版本 tag

如果你刚改了 README.md、依赖或项目描述,建议至少跑一遍:

make build
make metadata

如果你要正式发版,推荐直接走 publish-release-*,这样 commit、tag 和 push 都在同一个顺序化流程里,不容易再出现 tag 指到错误提交的问题。

快速开始

import asyncio
from pydantic import BaseModel, Field
from yier_agents import Agent, LLM, Tool, ToolContext, ToolOutput


# 1. 定义工具参数
class ReadParams(BaseModel):
    path: str = Field(description="文件路径")


# 2. 定义工具执行函数
async def read(params: ReadParams, ctx: ToolContext) -> ToolOutput:
    with open(params.path) as f:
        content = f.read()
    return ToolOutput(content=f"File content:\n{content}")


# 3. 创建工具
read_tool = Tool(
    name="read",
    description="读取文件内容",
    parameters=ReadParams,
    execute=read
)

# 4. 创建 Agent
llm = LLM(
    base_url="https://api.openai.com/v1",
    api_key="your-key",
    model="gpt-4"
)

agent = Agent(
    llm=llm,
    tools=[read_tool],
    system_prompt="你是一个文件助手",
    verbose=True  # 启用详细的调试输出
)

# 5. 运行
result = await agent.run("读取 README.md 并总结")
print(result.final_message)

模型接入仅使用 OpenAI-compatible Chat Completions 接口,配置为 base_url、api_key 和 model:

from yier_agents import LLM

llm = LLM(
    base_url="https://gateway.example/v1",
    api_key="your-key",
    model="your-model-id",
)

# 或显式从环境变量加载:
llm = LLM.from_env()

from_env() 读取 YIER_BASE_URL、YIER_API_KEY、YIER_MODEL,显式参数优先于环境值。模型 ID 原样发送,不做厂商推断或前缀转换。使用完调用 await llm.aclose(),或使用 async with LLM(...)。

调试模式

使用 verbose=True 参数可以查看 Agent 执行的详细过程,方便调试:

agent = Agent(
    llm=llm,
    tools=[tool1, tool2],
    verbose=True  # 启用详细输出
)

result = await agent.run("执行任务", "session-id")

输出示例:

ℹ ============================================================
ℹ Starting Agent execution (session: session-i...)
ℹ ============================================================
ℹ Added system prompt
ℹ User: 执行任务

ℹ ────────────────────────────────────────────────────────────
ℹ Iteration 1/20
ℹ ────────────────────────────────────────────────────────────
ℹ Calling LLM...
✓ LLM response received (finish_reason: tool_calls, usage: 150 tokens)
⚙ Executing 2 tool call(s)...
⚙   [1/2] read({"path": "README.md"})
⚙   [2/2] grep({"pattern": "Agent"})
✓ Received 2 tool result(s)
⚙   [1] File content: ...
⚙   [2] Found 5 matches

ℹ ────────────────────────────────────────────────────────────
ℹ Iteration 2/20
ℹ ────────────────────────────────────────────────────────────
ℹ Calling LLM...
✓ LLM response received (finish_reason: stop, usage: 200 tokens)
ℹ Content: 任务已完成
✓ Agent completed successfully
ℹ ============================================================

详见 verbose 示例。

架构

Agent (执行循环)
  ├─> LLM (API 调用层)
  ├─> ToolMiddleware (工具管理和验证)
  │     ├─> Tool (工具定义)
  │     └─> Context (执行上下文)
  ├─> MCPClient (MCP server 连接)
  │     ├─> stdio transport (子进程)
  │     └─> SSE transport (HTTP)
  └─> Message (消息管理)

Skills

Skill 用来打包一组工具和附加的 system prompt,适合构建你自己的可组合 Agent 能力层。

from yier_agents import Agent, LLM, Skill

network_skill = Skill(
    name="network-basics",
    description="Basic network utilities",
    tools=[get_ip_tool],
    system_prompt="Use get_ip when the user asks about the local machine IP."
)

agent = Agent(
    llm=llm,
    tools=[],
    skills=[network_skill],
    system_prompt="你是一个轻量但可靠的终端助手"
)

Lazy Skills

除了静态 Skill 之外,现在也支持 OpenCode 风格的按需加载 skills。它们从 SKILL.md 目录结构中发现,在系统提示里只暴露 <available_skills> 列表,真正需要时再通过内置 skill_load 工具加载完整内容。

支持的项目级目录:

  • .opencode/skill/<name>/SKILL.md
  • .opencode/skills/<name>/SKILL.md
  • .claude/skills/<name>/SKILL.md
  • .agents/skills/<name>/SKILL.md
from pathlib import Path
from yier_agents import Agent, LLM, SkillCatalog

catalog = SkillCatalog.discover(
    Path.cwd(),
    include_project=True,
    include_global=False,
)

agent = Agent(
    llm=LLM.from_env(),
    tools=[],
    skill_catalog=catalog,
    system_prompt="你是一个支持 lazy skills 的编程助手",
)

如果某个 skill 目录里包含 scripts/ 或 references/, skill_load 会把 skill 正文、base directory 和采样文件列表注入上下文。脚本不会自动执行,而是由后续普通工具去读取或运行。

内置文件/命令工具:

交互式 CLI 默认使用兼容 pi coding-agent 的短工具名,模型看到的是 read、bash、edit、write、grep、find 和 ls:

  • read - 读取文件内容并返回行号
  • bash - 在工作区执行 shell 命令
  • edit - 对文件做精确文本替换
  • write - 创建或更新文件
  • grep - 按文本或正则搜索文件内容,支持 glob、上下文行和大小写选项
  • find - 按 glob 查找文件和目录
  • ls - 浏览目录内容

Python API 使用同一套命名:create_read_tool、create_bash_tool、create_edit_tool、create_write_tool、create_grep_tool、create_find_tool、create_ls_tool。旧工厂和旧工具单例已移除,迁移对照见 CHANGELOG。

from pathlib import Path
from yier_agents import Agent, create_read_tool, create_grep_tool, create_find_tool

root = Path.cwd()
agent = Agent(
    llm=llm,
    tools=[factory([root], default_root=root) for factory in (
        create_read_tool, create_grep_tool, create_find_tool,
    )],
)

ToolOutput 结构

所有内置工具都会返回同一个 ToolOutput 结构:

  • content: 给模型和 CLI 看的可读摘要
  • metadata: 轻量摘要字段,适合列表、状态栏和简单 UI 绑定
  • raw: 给 UI 和外部调用方看的结构化原始载荷

推荐的消费顺序是:

  1. 用 raw 驱动 UI 展示和交互
  2. 用 metadata 做轻量状态判断或列表摘要
  3. 把 content 当作日志、回退展示或给模型继续阅读的文本
result = await tool.execute(params, ctx)

print(result.content)
print(result.metadata)
print(result.raw)

raw.kind 是最重要的分流字段。当前内置工具大致会返回这些类型:

  • shell_command: bash
  • terminal: terminal(窗口状态、增量输出、屏幕和等待结果)
  • file_read: read
  • file_list: ls
  • file_write: write
  • grep: grep
  • find: find
  • file_replace: edit
  • todo_list: todo_read
  • todo_update: todo_write
  • skill_load: skill_load
  • mcp_tool_result: 通过 MCPClient 代理的 MCP 工具
  • subagent_result: AgentTool
  • queued_followup: queue_terminal_followup
  • network_lookup: get_ip

Shell / Terminal

bash 返回 raw.kind="shell_command",包含 request、process、events 和 streams。运行期间通过 ToolCallUpdateEvent 实时推送 stdout/stderr;支持取消、可选超时与进程组清理,CLI 可用 Ctrl-C 停止当前运行。输出截断保留尾部,完整日志路径见 full_output_path。默认无超时,非零退出和超时会标为工具错误。完整接入见 Bash。

terminal 返回 raw.kind="terminal"。窗口操作返回 window、name、running、state、exit_code、尺寸和标题;读取另有 output、绝对字符游标 offset、丢弃字符数 skipped、truncated、waited 和 timed_out。PTY 将 stdout/stderr 合并为同一个有序输出流。

完整使用说明与迁移见 Terminal。

File / Todo / Skill / MCP

其他工具也在 raw 中提供结构化结果:文件读取的 lines、目录列表的 entries、grep 的 matches、find 的 paths、Todo 的 todos、Skill 的 sampled_files、MCP 的 contents 和子 Agent 的 final_message。宿主 UI 可以直接使用这些字段。

会话消息调度

库提供 SessionController:steer() 在当前模型请求及工具批次完成后注入,不打断工具;queue() 在当前整轮完成后依次启动新回合。支持消息 ID、状态事件、撤回、清空和取消后的显式恢复。CLI 运行中普通输入默认 steer,/queue <消息> 排下一轮,/messages 查看,/withdraw <id> 撤回,/resume 恢复。终端完成触发改用 /after <窗口> <消息>。

宿主示例、边界及异常语义见 SESSION_CONTROL.md。

Session Memory

默认 memory 仍可直接使用,但现在也支持持久化 store 和上下文压缩。

from pathlib import Path
from yier_agents import Agent, CompactionConfig, JSONSessionStore, LLM

agent = Agent(
    llm=LLM.from_env(),
    tools=[],
    session_store=JSONSessionStore(Path(".agent_storage/sessions")),
    compaction_config=CompactionConfig(
        enabled=True,
        trigger_message_count=24,
        preserve_recent_messages=8,
    ),
)

Interactive Assistant CLI

如果你想直接启动一个交互式个人助手,而不是自己写一层循环,可以直接运行包内 CLI:

python -m yier_agents.yier_cli

安装为可执行脚本后也可以直接运行:

yier-cli

CLI 读取 .env 和 YIER_BASE_URL、YIER_API_KEY、YIER_MODEL。交互式启动时仅询问缺失的地址、密钥或模型 ID;非交互模式缺少配置会立即报错。

这个入口默认启用:

  • 会话持久化记忆
  • 长上下文摘要压缩
  • lazy skills 发现与 /skills 浏览
  • 受限的文件、搜索、写入与命令工具
  • PTY 交互终端和 follow-up 排队
  • MCP 配置热重载

常用交互命令:

  • /skills [query] - 查看或筛选已发现的 skills
  • /ps [running|all] - 查看终端窗口
  • /tail <session_id> - 查看终端窗口最近输出
  • /wait <session_id> [seconds] - 等待终端退出一小段时间
  • /stop <session_id> - 关闭终端窗口
  • /after [list|<session_id> <message>] - 给终端挂一个完成后自动执行的 follow-up

一个典型流程是:

  1. 让 Agent 调用 terminal(command="new-window", shell_command="npm run dev", name="dev")。
  2. 通过 terminal 的 read、send-keys、capture-pane 和 kill-window 继续控制窗口。
  3. 用 /after 1 总结结果并告诉我下一步,或者让 Agent 调用 queue_terminal_followup。
  4. 终端退出后,CLI 将完成通知和输出摘要注入下一次 Agent 回合,并执行已排队的 follow-up。

也可以直接操作:/terminal new-window -n dev 'npm run dev'、/terminal send-keys -t dev C-c、/terminal capture-pane -t dev。/ps、/tail、/wait 和 /stop 继续作为终端窗口的快捷命令。

可以在 .yier.json 里为 CLI 覆盖这些默认值。默认行为和现在一致,只是搬进了配置层:

{
  "assistant": {
    "workspaceRoot": ".",
    "sessionStoragePath": ".agent_storage/sessions",
    "promptHistoryPath": ".agent_storage/prompt_history.txt",
    "allowedRoots": [
      ".",
      ".agent_storage/sessions"
    ],
    "includeSkillDirectoriesInAllowedRoots": true,
    "maxIterations": 100,
    "runCommand": {
      "allowShell": false,
      "shellProgram": "/bin/bash"
    },
    "compaction": {
      "enabled": true,
      "contextWindow": 32768,
      "reserveTokens": 4096,
      "keepRecentTokens": 8192,
      "summaryMaxTokens": 1024
    }
  }
}

create_bash_tool() 默认允许 shell 语法;CLI 仍遵循配置,runCommand.allowShell 默认为 false,此时 bash 不支持 |、重定向和链式 shell 语法;这是为了避免把普通命令执行提升成完整 shell。只有在你明确开启它时,才会用 shell 模式执行。

shellProgram 是可选覆盖项:类 Unix 系统默认使用 /bin/bash,Windows 默认使用当前系统的 ComSpec。terminal 使用相同的 shellProgram,通过 PTY 始终运行真实 shell,独立于 runCommand.allowShell。终端支持 Linux、macOS 和 WSL;Windows 原生暂不提供 ConPTY 后端。

MCP 支持

使用前请先安装可选依赖:pip install "yier_agents[mcp]"

通过 MCPClient 连接任意 MCP server,所有工具自动转换为 Tool 实例,与本地工具用法完全一致。

基于 mcp 2.x SDK:自动协商协议版本——server 支持 2026-07-28 新协议时走 server/discover 无握手连接,否则回退到传统 initialize 握手,stdio / SSE / Streamable HTTP 三种传输都兼容。

from yier_agents import MCPClient, Agent, LLM

llm = LLM.from_env()

# stdio 方式(本地子进程)
async with MCPClient.stdio("npx", ["-y", "@primevue/mcp"]) as client:
    tools = await client.get_tools()
    agent = Agent(llm=llm, tools=tools)
    result = await agent.run("DataTable 有哪些常用 props?", session_id="s1")

# SSE 方式(HTTP 远程)
async with MCPClient.sse("http://localhost:8000/sse") as client:
    tools = await client.get_tools()
    agent = Agent(llm=llm, tools=tools)
    result = await agent.run("执行任务", session_id="s2")

# 多个 MCP server 混合使用
async with (
    MCPClient.stdio("npx", ["-y", "@primevue/mcp"]) as mcp1,
    MCPClient.sse("http://localhost:8000/sse") as mcp2,
):
    tools = await mcp1.get_tools() + await mcp2.get_tools()
    agent = Agent(llm=llm, tools=tools)

一次连接,多个 Agent 共享:

async with MCPClient.stdio("npx", ["-y", "@primevue/mcp"]) as client:
    tools = await client.get_tools()  # 只连接一次

    agent1 = Agent(llm=llm, tools=tools, system_prompt="你是前端专家")
    agent2 = Agent(llm=llm, tools=tools, system_prompt="你是无障碍专家")

    # 两个 agent 共享同一个 MCP 连接
    r1, r2 = await asyncio.gather(
        agent1.run("DataTable 怎么分页?", "session-1"),
        agent2.run("Button 的无障碍属性?", "session-2"),
    )

详见 MCP 示例。

SubAgent 示例

# 创建专门的子 agent
search_agent = Agent(
    llm=llm,
    tools=[grep_tool, read_tool],
    system_prompt="你是代码搜索专家"
)

# 包装为工具
from yier_agents import AgentTool

search_tool = AgentTool(
    name="search_codebase",
    description="搜索和分析代码",
    agent=search_agent
)

# 主 agent 可以调用
main_agent = Agent(
    llm=llm,
    tools=[search_tool, edit_tool]
)

result = await main_agent.run("重构这个模块")

Todo 工具

内置的任务跟踪工具,让 AI 自动管理多步骤任务的进度。

from yier_agents import Agent, LLM, TodoWriteTool, TodoReadTool

# 创建带 todo 工具的 agent
agent = Agent(
    llm=llm,
    tools=[
        TodoWriteTool,  # AI 可以创建和更新任务列表
        TodoReadTool,   # AI 可以查看当前进度
        # ... 其他工具
    ],
    system_prompt="对于多步骤任务,使用 todo_write 工具跟踪进度。"
)

# AI 会自动使用 todo 工具管理任务
result = await agent.run("实现用户认证系统,包括登录、注册和密码重置")

AI 自动管理 todos:

  • 接收多步骤任务时自动创建 todo 列表
  • 开始每个任务前标记为 in_progress
  • 完成后标记为 completed
  • 实时跟踪进度

Todo 状态:

  • pending ⏸ - 待执行
  • in_progress ▶ - 执行中
  • completed ✓ - 已完成

详见 Todo 工具文档 和 示例。

开发

# 运行测试
pytest tests/ -v

# 运行特定测试
pytest tests/test_agent.py -v

# 查看覆盖率
pytest --cov=doc_agents tests/

设计文档

详细设计请参考:

License

MIT

Metadata

Release files for yier-agents 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yier-agents 0.4.0
File Size Uploaded Provenance Actions
yier_agents-0.4.0.tar.gz 198.2 kB With provenance Details for yier_agents-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for yier-agents 0.4.0
File Interpreter ABI Platform Actions
yier_agents-0.4.0-py3-none-any.whl Python 3 none any Details for yier_agents-0.4.0-py3-none-any.whl

Total release size: 375.4 kB

Release files / yier_agents-0.4.0.tar.gz

Download URL yier_agents-0.4.0.tar.gz
Size 198.2 kB
Tags Source
SHA-256 checksum
How to use checksums
73dcbc103a922d700b6ab8d3fb210d4783e789662eb9060693fa3db6c6206409
BLAKE2b-256 checksum
How to use checksums
b9f3c5ac7c2c04e54981319aae441c1c7efb0303f08991dabf29c35304b6ff1f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.

Transparency log

Release files / yier_agents-0.4.0-py3-none-any.whl

Download URL yier_agents-0.4.0-py3-none-any.whl
Size 177.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
adfbc37c9b997738a8f60e2e62493cfbb40d9d6f6b24cf69f63d109210c27dc5
BLAKE2b-256 checksum
How to use checksums
a788d03c96384426a856a3fffa35d4404bfa8b1ed9dd03a1f154378755c57d63
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.

Transparency log

Security for yier-agents 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for yier_agents-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page