@@ -33,6 +33,8 @@ Agent 通过以下步骤动态使用工具:
3333| [ Streaming Tools(流式工具)] ( #streaming-tools流式工具 ) | 实时预览长文本生成 | 使用 StreamingFunctionTool | 代码生成、文档写作 |
3434| [ WebFetchTool] ( #webfetchtool ) | 抓取并文本化单个公网 URL | 实例化 WebFetchTool 并加入 tools | 阅读文档页、RFC、changelog、新闻 |
3535| [ WebSearchTool] ( #websearchtool ) | 公网搜索引擎检索 | 实例化 WebSearchTool 并加入 tools | 实时资讯、版本发布、事实/定义查询 |
36+ | [ TodoWriteTool] ( #todowritetool-任务清单工具 ) | 多步任务规划与进度跟踪(整表替换) | 挂载 ` TodoWriteTool ` | 短清单、无依赖编排、token 不敏感 |
37+ | [ Task 工具族] ( #task-工具族结构化任务看板 ) | 结构化任务看板(按 id 增量更新 + 依赖) | 挂载 ` TaskToolSet ` | 长任务板、跨轮跟踪、blockedBy 依赖 |
3638| [ Agent Code Executor] ( ./code_executor.md ) | 自动生成并执行代码场景、数据处理场景 | 配置 CodeExecutor | API 自动调用、表格数据处理 |
3739---
3840
@@ -2845,3 +2847,196 @@ DuckDuckGo provider 在命中 instant answer 时,`summary` 字段会包含 DDG
28452847- ** DuckDuckGo 原始命中** (` ddg_raw_agent ` ,` dedup_urls=False ` ):保留 provider 原始召回列表,便于下游处理
28462848- ** Google 基线** (` google_agent ` ,` safe=active ` ):真实公网搜索 + 服务端单域 ` siteSearch ` + 客户端多域过滤 + 黑名单 + per-call ` lang ` 覆盖
28472849- ** Google 时效性 Agent** (` google_raw_agent ` ,` dateRestrict=m6 ` + ` dedup_urls=False ` ):只保留过去 6 个月索引的结果,适合"最新/what's new"类查询
2850+
2851+ ---
2852+
2853+ ## TodoWriteTool(任务清单工具)
2854+
2855+ ` TodoWriteTool ` 是框架内置的** 结构化任务清单工具** ,对齐 Claude Code / DeepAgents 的 ` TodoWrite ` 语义:模型通过单次 ` todo_write ` 调用发送** 完整、更新后的清单** ,工具校验后整体替换上一份清单,并将会话级 state 持久化,从而在多轮 ` Runner.run_async ` 之间保持计划与进度。
2856+
2857+ 适合** 步骤较少、无显式依赖边、希望实现简单** 的场景。若需要服务端分配 id、按 ` taskId ` 增量 patch、或 ` blockedBy ` / ` blocks ` 依赖编排,请改用下文 [ Task 工具族] ( #task-工具族结构化任务看板 ) 。
2858+
2859+ ### 功能特性
2860+
2861+ - ** 整表替换** :每次调用传入完整 ` todos ` 数组,新列表** 完全覆盖** 旧列表(不做智能 merge);唯一合法的清空方式是显式传入 ` todos: [] `
2862+ - ** 会话级持久化** :清单序列化为 JSON 写入 ` tool_context.state["todos[:<branch>]"] ` (默认前缀 ` todos ` ,** 勿用** ` temp: ` ——该前缀会被 ` BaseSessionService ` 剥离且不持久化)
2863+ - ** 子 Agent 隔离** :state key 追加 ` :<branch> ` ,父 / 子 Agent 各自维护独立清单
2864+ - ** 硬契约校验(代码强制)** :` content ` / ` activeForm ` 非空、至多一个 ` in_progress ` 、` content ` 全局唯一;违反时返回 ` INVALID_ARGS ` / ` INVALID_TODOS `
2865+ - ** Prompt 引导分层** :` DEFAULT_TODO_PROMPT ` 经 ` process_request ` 自动注入 system instruction,描述使用时机与写法;与硬契约分离
2866+ - ** 响应带回 diff** :成功时返回 ` {message, todos, oldTodos} ` ,便于前端 / CLI 直接渲染当前清单与变更
2867+ - ** 可选策略钩子** :` nudge_hooks ` 只读回调,可在成功响应 ` message ` 末尾追加策略提示(不得修改清单)
2868+ - ** 全部完成后自动清空** :` clear_on_all_done=True ` (默认)时,若传入列表全部为 ` completed ` ,持久化为空列表,避免历史项堆积
2869+
2870+ ### TodoWriteTool 参数
2871+
2872+ | 参数 | 类型 | 默认值 | 说明 |
2873+ | ------| ------| --------| ------|
2874+ | ` state_key_prefix ` | ` str ` | ` "todos" ` | state key 前缀;勿使用 ` temp: ` |
2875+ | ` clear_on_all_done ` | ` bool ` | ` True ` | 全部为 ` completed ` 时是否清空持久化列表 |
2876+ | ` default_nudge ` | ` str ` | 内置文案 | 每次成功响应的基础提示语 |
2877+ | ` nudge_hooks ` | ` Optional[List[NudgeHook]] ` | ` None ` | 只读策略钩子列表 |
2878+ | ` filters_name ` / ` filters ` | — | ` None ` | 透传给 ` BaseTool ` 的 Filter |
2879+
2880+ ** LLM 调用参数** (` todo_write ` ):
2881+
2882+ | 参数 | 类型 | 必填 | 说明 |
2883+ | ------| ------| ------| ------|
2884+ | ` todos ` | ` array ` | 是 | 完整清单;每项含 ` content ` (祈使句)、` activeForm ` (进行时)、` status ` (` pending ` / ` in_progress ` / ` completed ` ) |
2885+
2886+ ** 成功响应字段** :
2887+
2888+ | 字段 | 类型 | 说明 |
2889+ | ------| ------| ------|
2890+ | ` message ` | ` str ` | 基础 nudge + 钩子追加文案 |
2891+ | ` todos ` | ` array ` | 持久化后的当前清单 |
2892+ | ` oldTodos ` | ` array \| null ` | 更新前的清单(首次写入为 ` null ` ) |
2893+
2894+ ### 使用方式
2895+
2896+ ``` python
2897+ from trpc_agent_sdk.agents import LlmAgent
2898+ from trpc_agent_sdk.models import OpenAIModel
2899+ from trpc_agent_sdk.tools import TodoWriteTool
2900+
2901+ agent = LlmAgent(
2902+ name = " todo_planner" ,
2903+ model = OpenAIModel(model_name = " ..." , api_key = " ..." , base_url = " ..." ),
2904+ instruction = " 你是规划型助手,多步任务请用 todo_write 维护清单。" ,
2905+ tools = [TodoWriteTool()],
2906+ )
2907+ ```
2908+
2909+ 服务端 / 审计读取当前清单:
2910+
2911+ ``` python
2912+ from trpc_agent_sdk.tools import get_todos, render_todos
2913+
2914+ todos = get_todos(session, branch = agent.name)
2915+ print (render_todos(todos)) # ✅ / 🔄 / ⬜ 纯文本 checklist
2916+ ```
2917+
2918+ ### TodoWriteTool 与 Task 工具族对比
2919+
2920+ | 维度 | ` TodoWriteTool ` | ` TaskToolSet ` |
2921+ | --- | --- | --- |
2922+ | 工具数量 | 1(` todo_write ` ) | 4(` task_create ` / ` task_update ` / ` task_get ` / ` task_list ` ) |
2923+ | 更新方式 | 整表替换 | 按 ` taskId ` 增量 patch |
2924+ | 单项标识 | ` content ` (唯一键) | ` id ` (服务端分配) |
2925+ | 依赖编排 | 无 | ` blockedBy ` / ` blocks ` ,完成上游自动 unblock |
2926+ | state key | ` todos[:branch] ` | ` tasks[:branch] ` |
2927+ | 并行 tool 调用 | 整表覆盖,天然 last-write-wins | 内置 ` task_store_lock ` 串行化 RMW |
2928+
2929+ > ** 建议二选一挂载** ;同时挂载易让模型混用两套语义。
2930+
2931+ ### TodoWriteTool 完整示例
2932+
2933+ 见 [ examples/todo_tool/run_agent.py] ( ../../../examples/todo_tool/run_agent.py ) :同一 session 内多轮「规划 → 逐项完成」,每轮用 ` get_todos ` 读回持久化清单。
2934+
2935+ ---
2936+
2937+ ## Task 工具族(结构化任务看板)
2938+
2939+ ` TaskToolSet ` 暴露四个工具——` task_create ` 、` task_update ` 、` task_get ` 、` task_list ` ——对齐 Claude Code v2.1.142+ 的结构化 Task 能力。与 ` TodoWriteTool ` 的整表替换不同,Task 工具族采用** 按服务端分配的 ` id ` 增量更新** :创建时返回 id,后续用 ` task_update ` 局部修改状态、字段或依赖边。
2940+
2941+ 整个看板序列化为** 单个 JSON blob** 写入 ` tool_context.state["tasks[:<branch>]"] ` ,跨轮存活;` highwatermark ` 记录曾分配的最高 id,软删除(` status: deleted ` )后** 不会复用 id** 。
2942+
2943+ ### 功能特性
2944+
2945+ - ** 增量更新** :` task_create ` 分配 id;` task_update ` 按 ` taskId ` patch,无需重传整板
2946+ - ** 依赖编排** :` addBlockedBy ` / ` removeBlockedBy ` (及 ` addBlocks ` / ` removeBlocks ` )维护双向边;上游 ` completed ` 时自动从下游 ` blockedBy ` 移除并返回 ` unblocked `
2947+ - ** Token 优化** :` task_list ` 只返回摘要(省略 ` description ` );完整详情用 ` task_get `
2948+ - ** 硬契约校验** :` subject ` 非空、状态合法、依赖存在、** 无环** (` detect_cycle ` )、默认** 至多一个 ` in_progress ` ** (` enforce_single_in_progress ` ,可关)
2949+ - ** 并发安全** :` _TaskToolBase ` 在 load → mutate → save 外包 ` task_store_lock ` (按 session + branch),兼容 ` parallel_tool_calls=True ` 下同批并行调用
2950+ - ** Prompt 自动注入** :` DEFAULT_TASK_PROMPT ` 多工具挂载时只注入一次
2951+
2952+ ### TaskToolSet 构造参数
2953+
2954+ | 参数 | 类型 | 默认值 | 说明 |
2955+ | ------| ------| --------| ------|
2956+ | ` state_key_prefix ` | ` str ` | ` "tasks" ` | state key 前缀;勿使用 ` temp: ` |
2957+ | ` enforce_single_in_progress ` | ` bool ` | ` True ` | 设置某任务 ` in_progress ` 时,若已有其他 ` in_progress ` 则拒绝 |
2958+ | ` inject_prompt ` | ` bool ` | ` True ` | 是否向 system instruction 注入 ` DEFAULT_TASK_PROMPT ` |
2959+
2960+ ### 四个工具的 LLM 参数概要
2961+
2962+ ** ` task_create ` **
2963+
2964+ | 参数 | 必填 | 说明 |
2965+ | ------| ------| ------|
2966+ | ` subject ` | 是 | 短标题(祈使句) |
2967+ | ` description ` | 否 | 自由文本详情 |
2968+ | ` activeForm ` | 否 | 进行时文案 |
2969+ | ` metadata ` | 否 | 扩展键值 |
2970+
2971+ 返回 ` {task: {id, subject}, message} ` 。
2972+
2973+ ** ` task_update ` **
2974+
2975+ | 参数 | 必填 | 说明 |
2976+ | ------| ------| ------|
2977+ | ` taskId ` | 是 | 要更新的任务 id |
2978+ | ` status ` | 否 | ` pending ` / ` in_progress ` / ` completed ` / ` deleted ` |
2979+ | ` subject ` / ` description ` / ` activeForm ` / ` owner ` / ` metadata ` | 否 | 标量字段 patch |
2980+ | ` addBlockedBy ` / ` removeBlockedBy ` | 否 | 上游依赖 id 列表 |
2981+ | ` addBlocks ` / ` removeBlocks ` | 否 | 下游阻塞 id 列表 |
2982+
2983+ 返回 ` {task, unblocked, message} ` ;` unblocked ` 为因本次完成而解除阻塞的 pending 任务 id 列表。
2984+
2985+ ** ` task_get ` ** :` taskId ` (必填)→ 含 ` description ` 的完整记录。
2986+
2987+ ** ` task_list ` ** :可选 ` includeDeleted ` ;返回 ` {tasks, stats} ` ,摘要不含 ` description ` 。
2988+
2989+ ** 常见错误码** :` INVALID_ARGS ` 、` INVALID_DEPENDENCY ` 、` INVALID_STATUS ` 、` NOT_FOUND ` 。
2990+
2991+ ### 使用方式
2992+
2993+ ``` python
2994+ from trpc_agent_sdk.agents import LlmAgent
2995+ from trpc_agent_sdk.models import OpenAIModel
2996+ from trpc_agent_sdk.tools import TaskToolSet
2997+
2998+ agent = LlmAgent(
2999+ name = " task_planner" ,
3000+ model = OpenAIModel(model_name = " ..." , api_key = " ..." , base_url = " ..." ),
3001+ instruction = " 多步项目请用 task_create / task_update 维护看板。" ,
3002+ tools = [TaskToolSet()],
3003+ # parallel_tool_calls=True 时,同批多个 task 工具由 task_store_lock 保护 store 一致性
3004+ )
3005+ ```
3006+
3007+ 读回持久化看板(REST / 审计 / demo 收尾):
3008+
3009+ ``` python
3010+ from trpc_agent_sdk.tools import get_task_store, render_task_list
3011+
3012+ store = get_task_store(session, branch = agent.name)
3013+ print (render_task_list(store))
3014+ # ✅ #1 已完成
3015+ # 🔄 #2 进行中
3016+ # ⬜ #3 待办 (blocked by: 2)
3017+ ```
3018+
3019+ ### 依赖与解锁示例
3020+
3021+ ``` text
3022+ #1 设计表结构
3023+ ├──→ #2 实现 API ──→ #3 单元测试
3024+ └──→ #4 编写文档
3025+
3026+ #1 completed → unblocked: ['2', '4']
3027+ #2 completed → unblocked: ['3']
3028+ ```
3029+
3030+ ### Task 工具族最佳实践
3031+
3032+ - ** 规划与执行分离** :先 ` task_create ` 建板并 ` addBlockedBy ` ,再逐项 ` in_progress ` → ` completed `
3033+ - ** 不要编造 id** :只使用 ` task_create ` 返回的 id
3034+ - ** 并行调用** :开启 ` parallel_tool_calls=True ` 时,同 board 上的并发 ` task_create ` / ` task_update ` 由锁串行化;不同 ` branch ` 仍并行
3035+ - ** 与 TodoWrite 二选一** :长板 + 依赖用 Task;短清单用 TodoWrite
3036+
3037+ ### Task 工具族完整示例
3038+
3039+ | 示例 | 说明 |
3040+ | --- | --- |
3041+ | [ examples/task_tools] ( ../../../examples/task_tools/ ) | 多轮对话:依赖编排、逐项完成、跨轮 ` get_task_store ` 读回看板 |
3042+ | [ examples/task_tools_parallel] ( ../../../examples/task_tools_parallel/ ) | 验证 ` parallel_tool_calls ` 与 ` task_store_lock ` (Phase 1–2 无需 API Key) |
0 commit comments