Skip to content

feat: [可扩展性增强] 产物显式 hooks / middleware / capability 扩展点 #6

Description

@EpisodeYu

概述

生成产物增强一组面向用户自定义代码的扩展接口,重点补齐当前扩展体系里的三个缺口:

  1. hooks 从“单个无参、观察型 Hooks 子类”升级为可组合、可参数化、可显式配置的生命周期扩展点。
  2. 工具 / 模型调用增加薄 middleware / policy 层,支持审计、脱敏、校验、限流、缓存、重试、拒绝等横切能力,无需改核心 loop。
  3. 引入轻量 capability 包装模式与 forge add 样板,把 tools / hooks / prompt additions / config schema 等扩展打包成普通 Python 模块,提升产物可扩展性,但不引入任何 agent 编排框架。

本 issue 来自一次代码梳理 + 联网对比调研。当前 HarnessSmith 的方向是对的:薄注册表 + 装饰器 + config.yaml 接线;下一步要做的是把“能扩展”变成“好扩展、可发现、可配置、可验证”。

背景 / 现状

当前产物已提供这些自定义接口:

  • Tools:@registry.tool(...) / Registry.register(),由 tools allowlist + risk 控制暴露面。
  • Paradigms:@register_paradigm("name"),由 paradigms.enabled/default 选择。
  • Context conditions / strategies:@register_condition / @register_strategy,由 context.triggers / context.strategy 接线。
  • Memory backends:@register_memory,仅在 memory.enabled 生成时存在。
  • Hooks:Hooks.before_step/after_step/before_tool/after_tool/on_error,由 hooks: "pkg.mod:Class" 挂载。
  • Extensions loader:extensions: [pkg.mod],启动时 import 模块,让上述装饰器副作用生效。
  • Interaction:Asker / ToolConfirmer,支撑 ask_question 与 HITL tool confirmation。
  • Prompts / rules / MCP / Skills:作为运行期可调或 spec 开关能力,与注册表体系协作。

主要缺口:

  • hooks 只能配置一个无参类,不能多 hook 组合,不能从 config 传参数。
  • hook 粒度偏少:没有 before_model / after_model / wrap_model_call / wrap_tool_call
  • before_tool 目前是观察型;真正拒绝发生在 allowlist/HITL 边界,缺少显式 tool policy / middleware 契约。
  • extensions / hooks 已是运行期字段,但 Web /config 面板未暴露,用户仍需手改 YAML。
  • 独立扩展模块需要记得 import;AGENTS.md 中部分示例仍引导改内置文件或手动改 __init__
  • 没有 LLM provider registry;新增 provider 仍要改 llm.py / router。
  • 没有“扩展包”或 forge add 样板,用户要自己摸清文件位置、配置字段与测试方式。

竞品 / 主流 harness 参考

  • LangChain / LangGraph:middleware 已是一等扩展点,常见 hook 包括 before_agent / before_model / after_model / after_agentwrap_model_call / wrap_tool_call;HITL 依赖 checkpoint + interrupt。
  • OpenAI Agents SDK:提供 function tools、guardrails、handoffs、sessions、tracing,并区分 RunHooksAgentHooks;hook 粒度覆盖 agent / LLM / tool / handoff 生命周期。
  • Pydantic AI:用 Capabilities 打包 tools、instructions、model settings、hooks;适合做可复用扩展包。
  • AG2 / AutoGen:agent middleware 覆盖 on_turn / on_llm_call / on_tool_execution / on_human_input;另有工具级 middleware。
  • CrewAI:event bus + event listener 用于观测和集成;Flows 提供 state / guardrail / persistence。
  • LlamaIndex:Workflows 用 typed events + @step + Context store 管理显式流程和状态。

对 HarnessSmith 的启发:可以吸收 middleware / guardrail / capability / event 的思想,但实现必须保持 own-your-code + 薄产物:普通 Python 函数/类、显式配置、无 agent 框架依赖、关闭零痕迹。

方案概要

A. 显式 hooks 配置增强

将当前:

hooks: "agent_harness.harness.hooks:AuditHooks"

扩展为兼容旧写法的新结构:

hooks:
  - class: "agent_harness.ext.audit:AuditHooks"
    enabled: true
    config:
      redact_args: true
      log_tool_results: false
  - class: "agent_harness.ext.metrics:MetricsHooks"
    enabled: true

要求:

  • 兼容旧字符串写法。
  • 多 hook 按配置顺序执行;after_* 是否反向执行需明确并测试。
  • 单个 hook 异常走 on_error / debug log,避免吞掉核心 loop 错误语义。
  • Web 流式 _StreamHooks 继续能与用户 hooks 组合。

B. 增加 model/tool 生命周期点

在不把 hook 变成复杂引擎的前提下,补齐生命周期:

  • before_run / after_runbefore_turn / after_turn
  • before_model(messages, tools, profile)
  • after_model(response, usage, profile)
  • wrap_model_call(call_next, request) 可选,用于缓存 / fallback / retry / 观测。
  • before_tool(call) / after_tool(call, result) 保留。
  • wrap_tool_call(call_next, call) 或独立 ToolPolicy,用于参数校验 / 拒绝 / 结果脱敏 / 限流。
  • on_stream_delta / on_thinking_delta 可选,用于 UI/日志/指标。
  • on_budget_block / on_context_compact / on_session_checkpoint 可选,用于可观测性。

薄优先建议:先做 before_model / after_model / wrap_tool_callToolPolicy,不要一次性做全事件总线。

C. Tool policy / middleware

新增一个独立于 risk 的薄契约,使工具级策略显式可配:

tool_policies:
  - class: "agent_harness.ext.security:SecretBlockPolicy"
    tools: ["shell", "write_file", "desktop-commander__*"]
    config:
      block_patterns: ["sk-", "AKIA"]

能力:

  • 执行前校验参数,可返回拒绝 observation。
  • 执行后可脱敏结果或裁剪结果。
  • 可统计耗时 / token / result size。
  • 与现有 HITL confirm 分层:confirm 是内置人审 policy,tool policy 是用户扩展 policy。

D. Capability bundle

提供一个很薄的“能力包”模式,避免用户在多个文件里手动接线:

# src/agent_harness/ext/github_capability.py
from agent_harness.harness.capabilities import capability

@capability("github")
def github():
    return {
        "tools": [search_issues, create_issue],
        "hooks": [AuditHooks],
        "prompt_additions": ["You may use GitHub tools for repo operations."],
        "config_schema": GithubConfig,
        "env": ["GITHUB_TOKEN"],
    }

运行期:

capabilities:
  - module: "agent_harness.ext.github_capability"
    name: github
    enabled: true
    config:
      default_repo: "owner/repo"

注意:这不是插件框架 / marketplace,只是“一个模块声明一组普通 Python 扩展”的接线糖。

E. Web / CLI 可发现性补齐

  • Web /config 增加 Extensions / Hooks 页面或 System 页字段。
  • /registries 扩展到 tools、hooks、capabilities、policies、LLM providers。
  • info 输出:
    • 已 import 的 extension modules。
    • 已注册工具及 risk / allowlist / policy。
    • 已挂 hooks / tool policies / capabilities。
    • 未解析名字给出“把模块加入 extensions[]”的修复建议。

F. forge add 样板

新增开发期命令,不让产物运行期依赖 HarnessSmith:

harnessmith forge add tool my_tool
harnessmith forge add hook audit
harnessmith forge add paradigm review
harnessmith forge add memory-backend sqlite
harnessmith forge add capability github

输出:新增用户模块、测试样板、config.yaml 接线提示或安全 patch。forge add 属 v1+ 增量再生成方向,可拆独立 issue / slice。

交付物

生成产物模板层

  • harness/hooks.py.j2:新增 hook 组合器 / 新生命周期点 / 参数化构造约定。
  • harness/extensions.py.j2:加载多个 hooks / policies / capabilities;旧 hooks: string 兼容。
  • harness/paradigms/__init__.py.j2:在 generate() / run_tool() 边界接入 model/tool middleware。
  • harness/config.py.j2 + config.yaml.j2:新增 runtime 字段,保持 extra="forbid" 与注释清楚。
  • interfaces/cli.py.j2:更新 _prepare_runtime() / info 输出。
  • interfaces/web.py.j2 + web_index.html.j2:暴露 extensions / hooks / registries。
  • AGENTS.md.j2 / README.md.j2:统一推荐“独立模块 + extensions[]”;新增扩展示例。
  • tests/*.j2:覆盖 hooks 组合、旧写法兼容、model/tool middleware、Web/CLI 可发现性、黄金路径。

生成器层(可后续拆分)

  • forge add 样板命令:若纳入本片,需更新 generator/CLI/docs/tests;否则另立 issue。

任务拆解

  • 设计并实现 hooks 新配置模型,兼容旧字符串写法。
  • 实现 CompositeHooks / 参数化 hook 构造 / 顺序规则。
  • 在 LLM 调用边界补 before_model / after_model
  • 设计并实现最小 wrap_tool_callToolPolicy 契约。
  • Web /config 暴露 extensions / hooks;/registries 增补扩展注册项。
  • CLI info 增补 extensions/hooks/policies/capabilities/tool risk 与 allowlist 状态。
  • 更新 AGENTS.md 扩展指南,统一独立模块写法。
  • 补测试:模板单测 + 生成产物黄金路径 + 无框架依赖断言。
  • 评估是否把 capabilitiesforge add 纳入本片,或拆为后续 issue。

验收标准(退出门禁)

  • 旧配置 hooks: "pkg.mod:Class" 仍可用。
  • 新配置可挂多个 hook,且按文档顺序触发;Web _StreamHooks 与用户 hooks 可组合。
  • 一个自定义 hook 可通过 config 收到参数。
  • model 调用前后 hook 能观测 profile / messages / response / usage,不泄露密钥。
  • tool policy / middleware 可拒绝一次工具调用,loop 返回可供模型自纠的 ERROR observation,不崩溃。
  • extensions[] 导入失败、hook 类不存在、hook 类型不匹配时给出 clean ConfigError
  • Web /config 可编辑并保存 extensions/hooks;/registries 能看到自定义注册项。
  • CLI info 能列出扩展、hooks、工具 risk / allowlist / policy 状态。
  • 默认薄产物不新增运行期依赖;生成的 pyproject.toml 不含 langchain / langgraph / adk
  • 黄金路径绿:示例 / preset 生成 → uv sync && pytest → mock function-calling 工具调用。
  • 大改动回归:触及 loop/config/web/tests 时按 CLAUDE.md §5.2 跑全量 golden + Docker 冒烟 + uvx harnessmith new 冒烟。
  • ReadLints clean。

需人审决策(命中 CLAUDE.md §6 的点)

  • 可能改运行期配置 schema,但不一定改 HarnessSpec:若仅改产物 config.yaml / Config,不命中 §6.1;若把 capability / hook 作为生成期结构开关,则需人审。
  • 默认产物不得新增运行期依赖:本片必须用 stdlib + 已有依赖完成;如引入第三方 middleware/event 库则命中 §6.2,不建议。
  • 禁止 agent 编排框架:不得引入 LangChain / LangGraph / ADK / workflow DSL / 动态图引擎。
  • hook 是否允许改变控制流:需要定口径。建议:观察型 hooks 默认只观测;能拒绝/改写的能力放在显式 ToolPolicy / wrap_* 中,语义更清楚。
  • capability 是否进首版:能力包会提升体验,但可能扩大范围;可先做 hooks + tool policy,capability / forge add 后续拆片。

非目标

  • 不做通用插件 marketplace。
  • 不做 LangGraph / CrewAI Flow 式 workflow DSL。
  • 不把多 agent supervisor、RAG、eval 平台混进本片。
  • 不给默认产物增加新运行期依赖。
  • 不改变“产物运行期不依赖 HarnessSmith”的边界;forge add 若做,也只能是开发期 codemod。
  • 不把 hook 当生产级安全边界;真正隔离仍靠 Docker / 不编译危险能力 / 后端凭证作用域。

风险

  • 范围蔓延:middleware / capability 很容易演变成框架。必须坚持“普通 Python + 显式 registry + 显式 config”。
  • hook 顺序与异常语义:多 hook 组合后,异常传播、on_error、after 反向顺序需要写清并测试。
  • 密钥泄露路径:model/tool hooks 能看到 messages / arguments / results,文档和默认实现必须提醒 trace/debug/redaction 边界。
  • Web 配置面复杂度:新增列表型 hooks / policies 后,Web 表单要保持简单,不能拖累默认 UX。
  • 兼容性:旧 hooks 字符串、现有 extensions[]、现有 tests/presets 必须保持可用。

建议落地顺序

  1. P0:多 hooks + 参数化配置 + Web/CLI 可见。
  2. P0:model 调用 hooks + tool policy / tool middleware。
  3. P1:capability bundle(只做模块声明与接线,不做 marketplace)。
  4. P1:@register_llm_provider
  5. P1 / v1+:forge add 扩展样板。
  6. P2:产物内薄 eval / golden-task harness,用于验证自定义扩展。

参考

  • 项目定位与扩展原则:docs/02-development/00-overview.md §3 / §6 / §8。
  • 当前模板扩展点:harnessmith/templates/src/__project_slug__/harness/hooks.py.j2extensions.py.j2tools.py.j2context.py.j2paradigms/__init__.py.j2memory.py.j2
  • 当前入口接线:interfaces/cli.py.j2::_prepare_runtimeinterfaces/web.py.j2::_EDITABLE_FIELDS / /registries
  • 用户扩展指南:harnessmith/templates/AGENTS.md.j2
  • 外部参考:LangChain middleware、OpenAI Agents SDK lifecycle hooks / guardrails、Pydantic AI capabilities、AG2 middleware / tool middleware、CrewAI event listeners、LlamaIndex workflows。

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfeature新功能 / feature work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions