Plugins

Plugin Actions

说明 plugin action 的 command、api、execute 结构,以及执行上下文和协作式超时

Plugin Actions

plugin action 是 plugin 最直接的显式能力入口。

一个 action 主要由这些部分组成:

  • allowWhenDisabled
  • command
  • api
  • execute

最核心的是 execute

最小例子:

actions: {
  status: {
    execute: async ({ context }) => {
      return {
        success: true,
        data: {
          workspace_path: context.workspace_path,
        },
      };
    },
  },
}

execute 负责:

  • 接收结构化 payload
  • 执行业务逻辑
  • 返回 success / data / error / message

每次 Action 调用都会收到两个职责分离的只读输入:

  • context:稳定的 Agent 与 Workspace 能力,包括身份、文件、Shell、日志、Web、Sessions 和 Plugins
  • execution:单次调用的身份、取消信号、可选 Session 范围和当前 Step 快照

模型 Tool 调用时,execution.call_id 等于对应 Tool Call ID;Session 身份和可选交互端口位于 execution.session;当前生效的 workspace_envagent_systems 位于 execution.snapshot。CLI、HTTP 或 scheduler 直接调用时,运行时会自动生成 call_id 和取消信号,但没有 Session 范围。Action 应把 execution.abort_signal 传递给网络请求、轮询和长耗时任务。

command

command 用于 CLI 输入映射。

它适合定义:

  • 描述文本
  • commander 参数和选项
  • 从 CLI 输入到 payload 的映射

api

api 用于 HTTP action 输入映射。

它适合定义:

  • method
  • path
  • 从 HTTP 请求到 payload 的映射

timeout_ms

Action 可以声明协作式超时:

actions: {
  search: {
    timeout_ms: 30_000,
    execute: async ({ execution }) => {
      const response = await fetch("https://example.com", {
        signal: execution.abort_signal,
      });
      return { success: true, data: { status: response.status } };
    },
  },
}

超时会触发 execution.abort_signal。这是协作式约束,Action 必须把信号传给底层操作;业务失败不会改变 Plugin 的生命周期状态。

allowWhenDisabled

这是 plugin action 和普通运行态 action 一个很容易忽略的差异点。

它表示:

  • 即使 plugin 当前处于 disabled,某个 action 仍然允许执行

典型场景:

  • status
  • install
  • configure
  • models

也就是那些“你正是因为 plugin 还没可用,所以更需要先执行”的 action。

如果没有显式打开 allowWhenDisabled,disabled plugin 的普通 action 会被拦住。

action 的执行上下文是什么

Plugin Action 会刻意分开稳定能力与单次调用状态:从 context 读取 Agent 与 Workspace 服务,从 execution 读取调用身份、取消、Session 交互和当前 Step 快照。Plugin 产品配置仍由上游在构造 Plugin 实例时传入。

一个完整一些的例子

actions: {
  use: {
    allowWhenDisabled: true,
    command: {
      description: "切换默认 provider",
      mapInput({ args }) {
        return {
          provider: String(args[0] || ""),
        };
      },
    },
    execute: async ({ input }) => {
      const provider = String((input as { provider?: unknown }).provider || "").trim();
      if (!provider) {
        return {
          success: false,
          error: "provider is required",
          message: "provider is required",
        };
      }
      return {
        success: true,
        data: { provider },
      };
    },
  },
}

相关文档